From 7a5bce18ae4e38f67781716b2ff39c5ea3a0fd9d Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Wed, 3 Apr 2024 16:48:31 +0300 Subject: [PATCH] Extensive unit tests for the CommandObjects class (#3796) Write isolated unit test for the different methods of the CommandObjects class. These can be tested by themselves, without considerations like cluster, sentinel or other orthogonal aspects. Structure the tests into logical groups, similar to how the Redis commands are documented on the redis.io website. For each group of commands there is a corresponding test class. The main goal is to have the test code as readable as possible. The methods are kept to a minimum length in general. Sometimes, due to required data preparation, this is not possible. Another goal is to have this as a sort of documentation. Ideally someone who reads these tests should be able to grasp what the Redis commands are doing. This being said, the tests still focus on testing the client. For example negative cases are rarely included, and mostly when they impact the client, for example the parsing of the response. It is not the goal of these tests to test the Redis server itself. Co-authored-by: Gabriel Erzse --- pom.xml | 6 + .../CommandObjectsBitmapCommandsTest.java | 195 +++ ...CommandObjectsBloomFilterCommandsTest.java | 138 ++ ...mandObjectsCountMinSketchCommandsTest.java | 203 +++ ...ommandObjectsCuckooFilterCommandsTest.java | 192 +++ .../CommandObjectsGenericCommandsTest.java | 81 + .../CommandObjectsGeospatialCommandsTest.java | 701 ++++++++ .../CommandObjectsHashCommandsTest.java | 405 +++++ ...CommandObjectsHyperloglogCommandsTest.java | 94 + .../CommandObjectsJsonCommandsTest.java | 1434 ++++++++++++++++ .../CommandObjectsListCommandsTest.java | 663 ++++++++ .../CommandObjectsModulesTestBase.java | 19 + .../CommandObjectsScriptingCommandsTest.java | 815 +++++++++ ...mandObjectsSearchAndQueryCommandsTest.java | 255 +++ ...ndObjectsServerManagementCommandsTest.java | 92 + .../CommandObjectsSetCommandsTest.java | 373 ++++ .../CommandObjectsSortedSetCommandsTest.java | 1508 +++++++++++++++++ .../CommandObjectsStandaloneTestBase.java | 15 + .../CommandObjectsStreamCommandsTest.java | 1023 +++++++++++ .../CommandObjectsStringCommandsTest.java | 593 +++++++ .../CommandObjectsTDigestCommandsTest.java | 255 +++ .../CommandObjectsTestBase.java | 108 ++ .../CommandObjectsTimeSeriesCommandsTest.java | 622 +++++++ .../CommandObjectsTopkCommandsTest.java | 118 ++ ...jectsTriggersAndFunctionsCommandsTest.java | 66 + .../jedis/commands/commandobjects/Person.java | 49 + 26 files changed, 10023 insertions(+) create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBloomFilterCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCountMinSketchCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCuckooFilterCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGeospatialCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHyperloglogCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsServerManagementCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTDigestCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTimeSeriesCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTopkCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java create mode 100644 src/test/java/redis/clients/jedis/commands/commandobjects/Person.java diff --git a/pom.xml b/pom.xml index aee4077c83..402cd35842 100644 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,12 @@ ${jackson.version} test + + net.javacrumbs.json-unit + json-unit + 2.38.0 + test + diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java new file mode 100644 index 0000000000..5427447100 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java @@ -0,0 +1,195 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; + +import java.util.List; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.BitCountOption; +import redis.clients.jedis.args.BitOP; +import redis.clients.jedis.params.BitPosParams; + +/** + * Tests related to Bitmap commands. + */ +public class CommandObjectsBitmapCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsBitmapCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testSetbitAndGetbit() { + String key = "bitKey"; + long offset = 10; + + Boolean initialValue = exec(commandObjects.getbit(key, offset)); + assertThat(initialValue, equalTo(false)); + + Boolean setbit = exec(commandObjects.setbit(key, offset, true)); + assertThat(setbit, equalTo(false)); // original value returned + + Boolean finalValue = exec(commandObjects.getbit(key, offset)); + assertThat(finalValue, equalTo(true)); + } + + @Test + public void testSetbitAndGetbitBinary() { + byte[] key = "bitKeyBytes".getBytes(); + long offset = 10; + + Boolean initialValue = exec(commandObjects.getbit(key, offset)); + assertThat(initialValue, equalTo(false)); + + Boolean setbit = exec(commandObjects.setbit(key, offset, true)); + assertThat(setbit, equalTo(false)); // original value returned + + Boolean finalValue = exec(commandObjects.getbit(key, offset)); + assertThat(finalValue, equalTo(true)); + } + + @Test + public void testBitcount() { + String key = "bitcountKey"; + byte[] keyBytes = key.getBytes(); + + // Set some bits + exec(commandObjects.setbit(key, 1, true)); + exec(commandObjects.setbit(key, 2, true)); + exec(commandObjects.setbit(key, 7, true)); // This makes 1 byte with 3 bits set + exec(commandObjects.setbit(key, 8, true)); // Next byte, first bit set + + Long bitcountFullString = exec(commandObjects.bitcount(key)); + assertThat(bitcountFullString, equalTo(4L)); + + Long bitcountFirstByte = exec(commandObjects.bitcount(key, 0, 0)); + assertThat(bitcountFirstByte, equalTo(3L)); + + Long bitcountFullStringBinary = exec(commandObjects.bitcount(keyBytes)); + assertThat(bitcountFullStringBinary, equalTo(4L)); + + Long bitcountFirstByteBinary = exec(commandObjects.bitcount(keyBytes, 0, 0)); + assertThat(bitcountFirstByteBinary, equalTo(3L)); + + Long bitcountFirstSixBits = exec(commandObjects.bitcount(key, 0, 5, BitCountOption.BIT)); + assertThat(bitcountFirstSixBits, equalTo(2L)); + + Long bitcountFirstSixBitsBinary = exec(commandObjects.bitcount(keyBytes, 0, 5, BitCountOption.BIT)); + assertThat(bitcountFirstSixBitsBinary, equalTo(2L)); + } + + @Test + public void testBitpos() { + String key = "bitposKey"; + byte[] keyBytes = key.getBytes(); + + // Set some bits + exec(commandObjects.setbit(key, 10, true)); + exec(commandObjects.setbit(key, 22, true)); + exec(commandObjects.setbit(key, 30, true)); + + Long firstSetBit = exec(commandObjects.bitpos(key, true)); + assertThat(firstSetBit, equalTo(10L)); + + Long firstUnsetBit = exec(commandObjects.bitpos(key, false)); + assertThat(firstUnsetBit, equalTo(0L)); + + BitPosParams params = new BitPosParams(15, 25).modifier(BitCountOption.BIT); + + Long firstSetBitInRange = exec(commandObjects.bitpos(key, true, params)); + assertThat(firstSetBitInRange, equalTo(22L)); + + Long firstUnsetBitInRange = exec(commandObjects.bitpos(key, false, params)); + assertThat(firstUnsetBitInRange, equalTo(15L)); + + Long firstSetBitBinary = exec(commandObjects.bitpos(keyBytes, true)); + assertThat(firstSetBitBinary, equalTo(10L)); + + Long firstUnsetBitBinary = exec(commandObjects.bitpos(keyBytes, false)); + assertThat(firstUnsetBitBinary, equalTo(0L)); + + Long firstSetBitInRangeBinary = exec(commandObjects.bitpos(keyBytes, true, params)); + assertThat(firstSetBitInRangeBinary, equalTo(22L)); + + Long firstUnsetBitInRangeBinary = exec(commandObjects.bitpos(keyBytes, false, params)); + assertThat(firstUnsetBitInRangeBinary, equalTo(15L)); + } + + @Test + public void testBitfield() { + String key = "bitfieldKey"; + + List bitfieldResult = exec(commandObjects.bitfield( + key, "INCRBY", "i5", "100", "7", "GET", "i5", "100")); + + // Contains the result of the INCRBY operation, and the result of the GET operation. + assertThat(bitfieldResult, contains(7L, 7L)); + + List bitfieldRoResult = exec(commandObjects.bitfieldReadonly( + key, "GET", "i4", "100")); + assertThat(bitfieldRoResult, contains(3L)); + } + + @Test + public void testBitfieldBinary() { + byte[] key = "bitfieldKeyBytes".getBytes(); + + List bitfieldResult = exec(commandObjects.bitfield(key, + "INCRBY".getBytes(), "i5".getBytes(), "100".getBytes(), "7".getBytes(), + "GET".getBytes(), "i5".getBytes(), "100".getBytes())); + + // Contains the result of the INCRBY operation, and the result of the GET operation. + assertThat(bitfieldResult, contains(7L, 7L)); + + List bitfieldRoResult = exec(commandObjects.bitfieldReadonly(key, + "GET".getBytes(), "i4".getBytes(), "100".getBytes())); + assertThat(bitfieldRoResult, contains(3L)); + } + + @Test + public void testBitop() { + String srcKey1 = "srcKey1"; + String srcKey2 = "srcKey2"; + String destKey = "destKey"; + + // Set some bits + exec(commandObjects.setbit(srcKey1, 1, true)); + exec(commandObjects.setbit(srcKey1, 2, true)); + exec(commandObjects.setbit(srcKey1, 3, true)); + + exec(commandObjects.setbit(srcKey2, 1, true)); + exec(commandObjects.setbit(srcKey2, 3, true)); + + Long bitopResult = exec(commandObjects.bitop(BitOP.AND, destKey, srcKey1, srcKey2)); + assertThat(bitopResult, equalTo(1L)); // 1 byte stored + + assertThat(exec(commandObjects.getbit(destKey, 1)), equalTo(true)); + assertThat(exec(commandObjects.getbit(destKey, 2)), equalTo(false)); + assertThat(exec(commandObjects.getbit(destKey, 3)), equalTo(true)); + } + + @Test + public void testBitopBinary() { + byte[] srcKey1 = "srcKey1".getBytes(); + byte[] srcKey2 = "srcKey2".getBytes(); + byte[] destKey = "destKey".getBytes(); + + // Set some bits + exec(commandObjects.setbit(srcKey1, 1, true)); + exec(commandObjects.setbit(srcKey1, 2, true)); + exec(commandObjects.setbit(srcKey1, 3, true)); + + exec(commandObjects.setbit(srcKey2, 1, true)); + exec(commandObjects.setbit(srcKey2, 3, true)); + + Long bitopResult = exec(commandObjects.bitop(BitOP.XOR, destKey, srcKey1, srcKey2)); + assertThat(bitopResult, equalTo(1L)); // 1 byte stored + + assertThat(exec(commandObjects.getbit(new String(destKey), 1)), equalTo(false)); + assertThat(exec(commandObjects.getbit(new String(destKey), 2)), equalTo(true)); + assertThat(exec(commandObjects.getbit(new String(destKey), 3)), equalTo(false)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBloomFilterCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBloomFilterCommandsTest.java new file mode 100644 index 0000000000..a69bd8b68e --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBloomFilterCommandsTest.java @@ -0,0 +1,138 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.bloom.BFInsertParams; +import redis.clients.jedis.bloom.BFReserveParams; + +/** + * Tests related to Bloom Filter commands. + */ +public class CommandObjectsBloomFilterCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsBloomFilterCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testBfAddAndExists() { + String key = "testBf"; + + String reserve = exec(commandObjects.bfReserve(key, 0.01, 1000)); + assertThat(reserve, equalTo("OK")); + + boolean add = exec(commandObjects.bfAdd(key, "item1")); + assertThat(add, equalTo(true)); + + boolean exists = exec(commandObjects.bfExists(key, "item1")); + assertThat(exists, equalTo(true)); + + boolean notExists = exec(commandObjects.bfExists(key, "item2")); + assertThat(notExists, equalTo(false)); + } + + @Test + public void testBfInsert() { + String key = "testBf"; + + String reserve = exec(commandObjects.bfReserve(key, 0.01, 1000)); + assertThat(reserve, equalTo("OK")); + + List insert = exec(commandObjects.bfInsert(key, "item1", "item2")); + assertThat(insert, contains(true, true)); + + BFInsertParams insertParams = new BFInsertParams().noCreate().capacity(1000); + + List insertWithParams = exec(commandObjects.bfInsert(key, insertParams, "item1", "item2")); + assertThat(insertWithParams, contains(false, false)); + + assertThat(exec(commandObjects.bfExists(key, "item1")), equalTo(true)); + assertThat(exec(commandObjects.bfExists(key, "item2")), equalTo(true)); + assertThat(exec(commandObjects.bfExists(key, "item3")), equalTo(false)); + } + + @Test + public void testBfMAddMExistsAndCard() { + String key = "testBf"; + + String reserve = exec(commandObjects.bfReserve(key, 0.01, 1000)); + assertThat(reserve, equalTo("OK")); + + List mAdd = exec(commandObjects.bfMAdd(key, "item1", "item2", "item3")); + assertThat(mAdd, contains(true, true, true)); + + List mExists = exec(commandObjects.bfMExists(key, "item1", "item2", "item3", "item4")); + assertThat(mExists, contains(true, true, true, false)); + + Long card = exec(commandObjects.bfCard(key)); + assertThat(card, equalTo(3L)); + } + + @Test + public void testBfScanDumpAndLoadChunk() { + String key = "test"; + + String reserve = exec(commandObjects.bfReserve(key, 0.01, 5000)); + assertThat(reserve, equalTo("OK")); + + for (int i = 0; i < 1000; i++) { + Boolean add = exec(commandObjects.bfAdd(key, "item" + i)); + assertThat(add, equalTo(true)); + } + + String newKey = "testBfLoadChunk"; + + long iterator = 0; + do { + Map.Entry scanDumpResult = exec(commandObjects.bfScanDump(key, iterator)); + + iterator = scanDumpResult.getKey(); + + if (iterator > 0) { + byte[] data = scanDumpResult.getValue(); + + assertThat(data, notNullValue()); + + String loadChunk = exec(commandObjects.bfLoadChunk(newKey, iterator, data)); + assertThat(loadChunk, equalTo("OK")); + } + } while (iterator != 0); + + // verify destination + for (int i = 0; i < 1000; i++) { + Boolean exists = exec(commandObjects.bfExists(newKey, "item" + i)); + assertThat(exists, equalTo(true)); + } + + Boolean missingItem = exec(commandObjects.bfExists(newKey, "item1001")); + assertThat(missingItem, equalTo(false)); + } + + @Test + public void testBfInfo() { + String key = "testBf"; + + double errorRate = 0.01; + long capacity = 1000; + BFReserveParams reserveParams = new BFReserveParams().expansion(2); + + String reserve = exec(commandObjects.bfReserve(key, errorRate, capacity, reserveParams)); + assertThat(reserve, equalTo("OK")); + + Boolean add = exec(commandObjects.bfAdd(key, "item1")); + assertThat(add, equalTo(true)); + + Map info = exec(commandObjects.bfInfo(key)); + assertThat(info, hasEntry("Capacity", 1000L)); + assertThat(info, hasEntry("Number of items inserted", 1L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCountMinSketchCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCountMinSketchCommandsTest.java new file mode 100644 index 0000000000..c1be92acb4 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCountMinSketchCommandsTest.java @@ -0,0 +1,203 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; + +/** + * Tests related to Count-min sketch commands. + */ +public class CommandObjectsCountMinSketchCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsCountMinSketchCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testIncrByAndQuery() { + String key = "testCMS"; + + String init = exec(commandObjects.cmsInitByDim(key, 10000, 5)); + assertThat(init, equalTo("OK")); + + Map itemIncrements = new HashMap<>(); + itemIncrements.put("apple", 30L); + itemIncrements.put("banana", 20L); + itemIncrements.put("carrot", 10L); + + List incrBy = exec(commandObjects.cmsIncrBy(key, itemIncrements)); + // due to Map's unpredictable order, we can't assert ordering of the result + assertThat(incrBy, containsInAnyOrder(10L, 20L, 30L)); + + List query = exec(commandObjects.cmsQuery(key, "apple", "banana", "carrot", "date")); + + assertThat(query, notNullValue()); + assertThat(query.size(), equalTo(4)); + + assertThat(query.get(0), greaterThanOrEqualTo(30L)); // apple + assertThat(query.get(1), greaterThanOrEqualTo(20L)); // banana + assertThat(query.get(2), greaterThanOrEqualTo(10L)); // carrot + assertThat(query.get(3), lessThanOrEqualTo(1L)); // date, in practice, could be >0 due to estimation error + } + + @Test + public void testCMSInitByProb() { + String key = "testCMS"; + + String init = exec(commandObjects.cmsInitByProb(key, 0.01, 0.99)); + assertThat(init, equalTo("OK")); + + Map itemIncrements = new HashMap<>(); + itemIncrements.put("apple", 5L); + itemIncrements.put("banana", 3L); + itemIncrements.put("carrot", 8L); + + List incrBy = exec(commandObjects.cmsIncrBy(key, itemIncrements)); + assertThat(incrBy, containsInAnyOrder(3L, 5L, 8L)); + + List query = exec(commandObjects.cmsQuery(key, "apple", "banana", "carrot", "dragonfruit")); + + assertThat(query, notNullValue()); + assertThat(query.size(), equalTo(4)); + + assertThat(query.get(0), greaterThanOrEqualTo(5L)); // apple + assertThat(query.get(1), greaterThanOrEqualTo(3L)); // banana + assertThat(query.get(2), greaterThanOrEqualTo(8L)); // carrot + // "dragonfruit" was not incremented, its count should be minimal, but due to the probabilistic nature of CMS, it might not be exactly 0. + assertThat(query.get(3), lessThanOrEqualTo(1L)); + } + + @Test + public void testCMSMerge() { + String cmsKey1 = "testCMS1"; + String cmsKey2 = "testCMS2"; + String cmsDestKey = "testCMSMerged"; + + long width = 10000; + long depth = 5; + + String init1 = exec(commandObjects.cmsInitByDim(cmsKey1, width, depth)); + assertThat(init1, equalTo("OK")); + + String init2 = exec(commandObjects.cmsInitByDim(cmsKey2, width, depth)); + assertThat(init2, equalTo("OK")); + + Map itemIncrements1 = new HashMap<>(); + itemIncrements1.put("apple", 2L); + itemIncrements1.put("banana", 3L); + + List incrBy1 = exec(commandObjects.cmsIncrBy(cmsKey1, itemIncrements1)); + assertThat(incrBy1, containsInAnyOrder(2L, 3L)); + + Map itemIncrements2 = new HashMap<>(); + itemIncrements2.put("carrot", 5L); + itemIncrements2.put("date", 4L); + + List incrBy2 = exec(commandObjects.cmsIncrBy(cmsKey2, itemIncrements2)); + assertThat(incrBy2, containsInAnyOrder(4L, 5L)); + + String init3 = exec(commandObjects.cmsInitByDim(cmsDestKey, width, depth)); + assertThat(init3, equalTo("OK")); + + String merge = exec(commandObjects.cmsMerge(cmsDestKey, cmsKey1, cmsKey2)); + assertThat(merge, equalTo("OK")); + + List query = exec(commandObjects.cmsQuery(cmsDestKey, "apple", "banana", "carrot", "date")); + + assertThat(query, notNullValue()); + assertThat(query.size(), equalTo(4)); + + assertThat(query.get(0), greaterThanOrEqualTo(2L)); // apple + assertThat(query.get(1), greaterThanOrEqualTo(3L)); // banana + assertThat(query.get(2), greaterThanOrEqualTo(5L)); // carrot + assertThat(query.get(3), greaterThanOrEqualTo(4L)); // date + } + + @Test + public void testCMSMergeWithWeights() { + String cmsKey1 = "testCMS1"; + String cmsKey2 = "testCMS2"; + String cmsDestKey = "testCMSMerged"; + + long width = 10000; + long depth = 5; + + String init1 = exec(commandObjects.cmsInitByDim(cmsKey1, width, depth)); + assertThat(init1, equalTo("OK")); + + String init2 = exec(commandObjects.cmsInitByDim(cmsKey2, width, depth)); + assertThat(init2, equalTo("OK")); + + Map itemIncrements1 = new HashMap<>(); + itemIncrements1.put("apple", 2L); + itemIncrements1.put("banana", 3L); + + List incrBy1 = exec(commandObjects.cmsIncrBy(cmsKey1, itemIncrements1)); + assertThat(incrBy1, containsInAnyOrder(2L, 3L)); + + Map itemIncrements2 = new HashMap<>(); + itemIncrements2.put("carrot", 5L); + itemIncrements2.put("date", 4L); + + List incrBy2 = exec(commandObjects.cmsIncrBy(cmsKey2, itemIncrements2)); + assertThat(incrBy2, containsInAnyOrder(4L, 5L)); + + String init3 = exec(commandObjects.cmsInitByDim(cmsDestKey, width, depth)); + assertThat(init3, equalTo("OK")); + + // Weights for the CMS keys to be merged + Map keysAndWeights = new HashMap<>(); + keysAndWeights.put(cmsKey1, 1L); + keysAndWeights.put(cmsKey2, 2L); + + String merge = exec(commandObjects.cmsMerge(cmsDestKey, keysAndWeights)); + assertThat(merge, equalTo("OK")); + + List query = exec(commandObjects.cmsQuery(cmsDestKey, "apple", "banana", "carrot", "date")); + + assertThat(query, notNullValue()); + assertThat(query.size(), equalTo(4)); + + assertThat(query.get(0), greaterThanOrEqualTo(2L)); // apple, weight of 1 + assertThat(query.get(1), greaterThanOrEqualTo(3L)); // banana, weight of 1 + assertThat(query.get(2), greaterThanOrEqualTo(10L)); // carrot, weight of 2, so 5 * 2 + assertThat(query.get(3), greaterThanOrEqualTo(8L)); // date, weight of 2, so 4 * 2 + } + + @Test + public void testCMSInfo() { + String key = "testCMS"; + + long width = 10000; + long depth = 5; + + String init = exec(commandObjects.cmsInitByDim(key, width, depth)); + assertThat(init, equalTo("OK")); + + Map itemIncrements = new HashMap<>(); + itemIncrements.put("apple", 3L); + itemIncrements.put("banana", 2L); + itemIncrements.put("carrot", 1L); + + List incrBy = exec(commandObjects.cmsIncrBy(key, itemIncrements)); + assertThat(incrBy, hasSize(3)); + + Map info = exec(commandObjects.cmsInfo(key)); + + assertThat(info, hasEntry("width", 10000L)); + assertThat(info, hasEntry("depth", 5L)); + assertThat(info, hasEntry("count", 6L)); // 3 + 2 + 1 + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCuckooFilterCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCuckooFilterCommandsTest.java new file mode 100644 index 0000000000..68bc9b7060 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsCuckooFilterCommandsTest.java @@ -0,0 +1,192 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.bloom.CFInsertParams; +import redis.clients.jedis.bloom.CFReserveParams; + +/** + * Tests related to Cuckoo filter commands. + */ +public class CommandObjectsCuckooFilterCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsCuckooFilterCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testCuckooFilterAdd() { + String key = "testCuckooFilter"; + + String reserve = exec(commandObjects.cfReserve(key, 1000)); + assertThat(reserve, equalTo("OK")); + + Boolean add = exec(commandObjects.cfAdd(key, "apple")); + assertThat(add, equalTo(true)); + + Boolean addNx = exec(commandObjects.cfAddNx(key, "apple")); + assertThat(addNx, equalTo(false)); // "apple" already exists, NX makes this fail + + Boolean addNx2 = exec(commandObjects.cfAddNx(key, "banana")); + assertThat(addNx2, equalTo(true)); + + Long count = exec(commandObjects.cfCount(key, "apple")); + assertThat(count, greaterThanOrEqualTo(1L)); + } + + @Test + public void testCuckooFilterReserveInsertAndCount() { + String key = "testCuckooFilterAdvanced"; + + CFReserveParams reserveParams = new CFReserveParams() + .bucketSize(4).maxIterations(500).expansion(1); + + String reserve = exec(commandObjects.cfReserve(key, 5000, reserveParams)); + assertThat(reserve, equalTo("OK")); + + List insert = exec(commandObjects.cfInsert( + key, "apple", "banana", "carrot", "date")); + assertThat(insert, everyItem(equalTo(true))); + + CFInsertParams insertParams = new CFInsertParams().noCreate(); + + List insertWithParams = exec(commandObjects.cfInsert( + key, insertParams, "eggplant", "fig", "grape", "apple")); + assertThat(insertWithParams, everyItem(equalTo(true))); + + Long countApple = exec(commandObjects.cfCount(key, "apple")); + assertThat(countApple, greaterThanOrEqualTo(2L)); + + Long countBanana = exec(commandObjects.cfCount(key, "banana")); + assertThat(countBanana, greaterThanOrEqualTo(1L)); + + Long countNonExisting = exec(commandObjects.cfCount(key, "watermelon")); + assertThat(countNonExisting, equalTo(0L)); + } + + @Test + public void testCuckooFilterInsertNx() { + String key = "testCf"; + + String[] items = { "item1", "item2", "item3" }; + + CFInsertParams insertParams = new CFInsertParams().capacity(1000L).noCreate(); + + List insertNx1 = exec(commandObjects.cfInsertNx(key, items)); + assertThat(insertNx1, not(empty())); + assertThat(insertNx1, everyItem(equalTo(true))); + + long countAfterFirstInsert = exec(commandObjects.cfCount(key, "item1")); + assertThat(countAfterFirstInsert, greaterThanOrEqualTo(1L)); + + List insertNx2 = exec(commandObjects.cfInsertNx(key, insertParams, items)); + assertThat(insertNx2, not(empty())); + assertThat(insertNx2, everyItem(equalTo(false))); + + long countAfterSecondInsert = exec(commandObjects.cfCount(key, "item1")); + assertThat(countAfterSecondInsert, greaterThanOrEqualTo(1L)); // count should remain the same + } + + @Test + public void testCuckooFilterExistsAndDel() { + String key = "testCf"; + String item = "item1"; + + boolean existsBeforeInsert = exec(commandObjects.cfExists(key, item)); + assertThat(existsBeforeInsert, equalTo(false)); + + Boolean add = exec(commandObjects.cfAdd(key, item)); + assertThat(add, equalTo(true)); + + boolean existsAfterInsert = exec(commandObjects.cfExists(key, item)); + assertThat(existsAfterInsert, equalTo(true)); + + boolean delete = exec(commandObjects.cfDel(key, item)); + assertThat(delete, equalTo(true)); + + boolean existsAfterDelete = exec(commandObjects.cfExists(key, item)); + assertThat(existsAfterDelete, equalTo(false)); + } + + @Test + public void testCuckooFilterMExists() { + String key = "testCf"; + + exec(commandObjects.cfInsert(key, "item1", "item2", "item3")); + + List mExists = exec(commandObjects.cfMExists( + key, "item1", "item2", "item3", "item4", "item5")); + + assertThat(mExists, contains(true, true, true, false, false)); + } + + @Test + public void testCuckooFilterScanDumpAndLoadChunk() { + long capacity = 5000; + + CFReserveParams reserveParams = new CFReserveParams() + .bucketSize(4).maxIterations(500).expansion(1); + + String key = "testCf"; + + String reserve = exec(commandObjects.cfReserve(key, capacity, reserveParams)); + assertThat(reserve, equalTo("OK")); + + // add some items to the source + for (int i = 0; i < 1000; i++) { + exec(commandObjects.cfAdd(key, "item" + i)); + } + + String newKey = "testCfLoadChunk"; + + // scandump and load + long iterator = 0; + do { + Map.Entry scanDumpResult = exec(commandObjects.cfScanDump(key, iterator)); + + iterator = scanDumpResult.getKey(); + if (iterator > 0) { + byte[] data = scanDumpResult.getValue(); + assertThat(data, notNullValue()); + + String loadChunk = exec(commandObjects.cfLoadChunk(newKey, iterator, data)); + assertThat(loadChunk, equalTo("OK")); + } + } while (iterator != 0); + + // verify destination + for (int i = 0; i < 1000; i++) { + boolean exists = exec(commandObjects.cfExists(newKey, "item" + i)); + assertThat(exists, equalTo(true)); + } + + boolean missingItem = exec(commandObjects.cfExists(newKey, "item1001")); + assertThat(missingItem, equalTo(false)); + } + + @Test + public void testCuckooFilterInfo() { + String key = "testCfInfo"; + + exec(commandObjects.cfReserve(key, 1000)); + + exec(commandObjects.cfAdd(key, "item1")); + + Map info = exec(commandObjects.cfInfo(key)); + + assertThat(info, hasEntry("Number of items inserted", 1L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java new file mode 100644 index 0000000000..0182de207f --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java @@ -0,0 +1,81 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import org.junit.Test; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.RedisProtocol; + +/** + * Tests related to Generic commands. + */ +public class CommandObjectsGenericCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsGenericCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testCopy() { + String srcKey = "sourceKey"; + String dstKey = "destinationKey"; + int dstDB = 1; + + exec(commandObjects.set(srcKey, "initialValue")); + + Boolean existsAfterSet = exec(commandObjects.exists(srcKey)); + assertThat(existsAfterSet, equalTo(true)); + + Boolean copy = exec(commandObjects.copy(srcKey, dstKey, dstDB, true)); + assertThat(copy, equalTo(true)); + + assertKeyExists(dstDB, dstKey, "initialValue"); + + // Update source + exec(commandObjects.set(srcKey, "newValue")); + + // Copy again without replace, it fails since dstKey already exists + Boolean secondCopy = exec(commandObjects.copy(srcKey, dstKey, dstDB, false)); + assertThat(secondCopy, equalTo(false)); + + assertKeyExists(dstDB, dstKey, "initialValue"); + } + + @Test + public void testCopyBinary() { + String srcKey = "sourceKey"; + String dstKey = "destinationKey"; + int dstDB = 1; + + exec(commandObjects.set(srcKey, "initialValue")); + + Boolean existsAfterSet = exec(commandObjects.exists(srcKey)); + assertThat(existsAfterSet, equalTo(true)); + + Boolean copy = exec(commandObjects.copy( + srcKey.getBytes(), dstKey.getBytes(), dstDB, true)); + assertThat(copy, equalTo(true)); + + assertKeyExists(dstDB, dstKey, "initialValue"); + + // Update source + exec(commandObjects.set(srcKey, "newValue")); + + // Copy again without replace, it will fail + Boolean secondCopy = exec(commandObjects.copy(srcKey.getBytes(), dstKey.getBytes(), dstDB, false)); + assertThat(secondCopy, equalTo(false)); + + assertKeyExists(dstDB, dstKey, "initialValue"); + } + + private void assertKeyExists(int dstDb, String key, Object expectedValue) { + // Cheat and use Jedis, it gives us access to any db. + try (Jedis jedis = new Jedis(nodeInfo)) { + jedis.auth("foobared"); + jedis.select(dstDb); + assertThat(jedis.get(key), equalTo(expectedValue)); + } + } + +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGeospatialCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGeospatialCommandsTest.java new file mode 100644 index 0000000000..bcdcd54092 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGeospatialCommandsTest.java @@ -0,0 +1,701 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.Test; +import redis.clients.jedis.GeoCoordinate; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.GeoUnit; +import redis.clients.jedis.params.GeoAddParams; +import redis.clients.jedis.params.GeoRadiusParam; +import redis.clients.jedis.params.GeoRadiusStoreParam; +import redis.clients.jedis.params.GeoSearchParam; +import redis.clients.jedis.resps.GeoRadiusResponse; + +/** + * Tests related to Geospatial commands. + */ +public class CommandObjectsGeospatialCommandsTest extends CommandObjectsStandaloneTestBase { + + // Some coordinates for testing + public static final String CATANIA = "Catania"; + public static final double CATANIA_LATITUDE = 37.502669; + public static final double CATANIA_LONGITUDE = 15.087269; + + public static final String PALERMO = "Palermo"; + public static final double PALERMO_LONGITUDE = 13.361389; + public static final double PALERMO_LATITUDE = 38.115556; + + public static final String SYRACUSE = "Syracuse"; + public static final double SYRACUSE_LONGITUDE = 15.293331; + public static final double SYRACUSE_LATITUDE = 37.075474; + + public static final String AGRIGENTO = "Agrigento"; + public static final double AGRIGENTO_LONGITUDE = 13.583333; + public static final double AGRIGENTO_LATITUDE = 37.316667; + + public CommandObjectsGeospatialCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testGeoAddAndRadius() { + String key = "locations"; + + Map cataniaCoordinates = new HashMap<>(); + cataniaCoordinates.put(CATANIA, new GeoCoordinate(CATANIA_LONGITUDE, CATANIA_LATITUDE)); + + Map syracuseCoordinates = new HashMap<>(); + syracuseCoordinates.put(SYRACUSE, new GeoCoordinate(SYRACUSE_LONGITUDE, SYRACUSE_LATITUDE)); + + Long addPalermo = exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + assertThat(addPalermo, equalTo(1L)); + + List radiusFromPalermo = exec(commandObjects.georadius( + key, PALERMO_LONGITUDE, PALERMO_LATITUDE, 100, GeoUnit.KM)); + assertThat(radiusFromPalermo.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + contains(equalTo(PALERMO))); + + Long addCatania = exec(commandObjects.geoadd(key, cataniaCoordinates)); + assertThat(addCatania, equalTo(1L)); + + List radiusFromCatania = exec(commandObjects.georadius( + key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 100, GeoUnit.KM)); + assertThat(radiusFromCatania.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + contains(equalTo(CATANIA))); + + Long addSyracuse = exec(commandObjects.geoadd(key, GeoAddParams.geoAddParams().nx(), syracuseCoordinates)); + assertThat(addSyracuse, equalTo(1L)); + + List radiusEverything = exec(commandObjects.georadius( + key, 15, 37, 200, GeoUnit.KM)); + assertThat(radiusEverything.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(equalTo(CATANIA), equalTo(SYRACUSE), equalTo(PALERMO))); + } + + @Test + public void testGeoAddAndRadiusBinary() { + byte[] key = "locations".getBytes(); + + Map cataniaCoordinates = new HashMap<>(); + cataniaCoordinates.put(CATANIA.getBytes(), new GeoCoordinate(CATANIA_LONGITUDE, CATANIA_LATITUDE)); + + Map syracuseCoordinates = new HashMap<>(); + syracuseCoordinates.put(SYRACUSE.getBytes(), new GeoCoordinate(SYRACUSE_LONGITUDE, SYRACUSE_LATITUDE)); + + Long addPalermo = exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO.getBytes())); + assertThat(addPalermo, equalTo(1L)); + + List radiusFromPalermo = exec(commandObjects.georadius( + key, PALERMO_LONGITUDE, PALERMO_LATITUDE, 100, GeoUnit.KM)); + assertThat(radiusFromPalermo.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + contains(equalTo(PALERMO.getBytes()))); + + Long addCatania = exec(commandObjects.geoadd(key, cataniaCoordinates)); + assertThat(addCatania, equalTo(1L)); + + List radiusFromCatania = exec(commandObjects.georadius( + key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 100, GeoUnit.KM)); + assertThat(radiusFromCatania.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + contains(equalTo(CATANIA.getBytes()))); + + Long addSyracuse = exec(commandObjects.geoadd(key, GeoAddParams.geoAddParams().nx(), syracuseCoordinates)); + assertThat(addSyracuse, equalTo(1L)); + + List radiusEverything = exec(commandObjects.georadius( + key, 15, 37, 200, GeoUnit.KM)); + assertThat(radiusEverything.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + containsInAnyOrder(equalTo(CATANIA.getBytes()), equalTo(PALERMO.getBytes()), equalTo(SYRACUSE.getBytes()))); + } + + @Test + public void testGeoDist() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + // Add locations to calculate distance + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + + Double distance = exec(commandObjects.geodist(key, CATANIA, PALERMO)); + // This is in meters, we don't try to accurately assert it. We refer to it later. + assertThat(distance, notNullValue()); + + Double distanceWithUnit = exec(commandObjects.geodist(key, CATANIA, PALERMO, GeoUnit.KM)); + assertThat(distanceWithUnit, closeTo(distance / 1000, 0.001)); + + Double binaryDistance = exec(commandObjects.geodist(binaryKey, CATANIA.getBytes(), PALERMO.getBytes())); + assertThat(binaryDistance, closeTo(distance, 0.001)); + + Double binaryDistanceWithUnit = exec(commandObjects.geodist(binaryKey, CATANIA.getBytes(), PALERMO.getBytes(), GeoUnit.KM)); + assertThat(binaryDistanceWithUnit, closeTo(distance / 1000, 0.001)); + } + + @Test + public void testGeoHash() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + + List hashes = exec(commandObjects.geohash(key, CATANIA, PALERMO)); + assertThat(hashes, contains(notNullValue(), notNullValue())); + + List binaryHashes = exec(commandObjects.geohash(binaryKey, CATANIA.getBytes(), PALERMO.getBytes())); + assertThat(binaryHashes, contains(hashes.get(0).getBytes(), hashes.get(1).getBytes())); + } + + @Test + public void testGeoPos() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + + List positions = exec(commandObjects.geopos(key, CATANIA, PALERMO)); + assertThat(positions.size(), equalTo(2)); + + assertThat(positions.get(0), notNullValue()); + assertThat(positions.get(0).getLongitude(), closeTo(CATANIA_LONGITUDE, 0.001)); + assertThat(positions.get(0).getLatitude(), closeTo(CATANIA_LATITUDE, 0.001)); + + assertThat(positions.get(1), notNullValue()); + assertThat(positions.get(1).getLongitude(), closeTo(PALERMO_LONGITUDE, 0.001)); + assertThat(positions.get(1).getLatitude(), closeTo(PALERMO_LATITUDE, 0.001)); + + List binaryPositions = exec(commandObjects.geopos(binaryKey, CATANIA.getBytes(), PALERMO.getBytes())); + assertThat(binaryPositions.size(), equalTo(2)); + + assertThat(binaryPositions.get(0), notNullValue()); + assertThat(binaryPositions.get(0).getLongitude(), closeTo(CATANIA_LONGITUDE, 0.001)); + assertThat(binaryPositions.get(0).getLatitude(), closeTo(CATANIA_LATITUDE, 0.001)); + + assertThat(binaryPositions.get(1), notNullValue()); + assertThat(binaryPositions.get(1).getLongitude(), closeTo(PALERMO_LONGITUDE, 0.001)); + assertThat(binaryPositions.get(1).getLatitude(), closeTo(PALERMO_LATITUDE, 0.001)); + } + + @Test + public void testGeoRadius() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withCoord().withDist(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + + List responses = exec(commandObjects.georadius(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM)); + + // we got distances, but no coordinates + assertThat(responses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(responses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List responsesWithParam = exec(commandObjects.georadius(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM, param)); + + // we got distances, and coordinates + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(CATANIA_LATITUDE, 0.001))); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(CATANIA_LONGITUDE, 0.001))); + + List binaryResponses = exec(commandObjects.georadius(binaryKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM)); + + // distances, but no coordinates + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List binaryResponsesWithParam = exec(commandObjects.georadius(binaryKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM, param)); + + // distances, and coordinates + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + containsInAnyOrder(CATANIA.getBytes(), PALERMO.getBytes())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(CATANIA_LATITUDE, 0.001))); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(CATANIA_LONGITUDE, 0.001))); + } + + @Test + public void testGeoRadiusReadonly() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withCoord().withDist(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + + List responses = exec(commandObjects.georadiusReadonly(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM)); + + // we got distances, but no coordinates + assertThat(responses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(responses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List responsesWithParam = exec(commandObjects.georadiusReadonly(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM, param)); + + // we got distances, and coordinates + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(CATANIA_LATITUDE, 0.001))); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(CATANIA_LONGITUDE, 0.001))); + + List binaryResponses = exec(commandObjects.georadiusReadonly(binaryKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM)); + + // distances, but no coordinates + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(CATANIA, PALERMO)); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List binaryResponsesWithParam = exec(commandObjects.georadiusReadonly(binaryKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, 200, GeoUnit.KM, param)); + + // distances, and coordinates + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + containsInAnyOrder(CATANIA.getBytes(), PALERMO.getBytes())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(CATANIA_LATITUDE, 0.001))); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(CATANIA_LONGITUDE, 0.001))); + } + + @Test + public void testGeoRadiusByMember() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withCoord().withDist(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(key, AGRIGENTO_LONGITUDE, AGRIGENTO_LATITUDE, AGRIGENTO)); + + List responses = exec(commandObjects.georadiusByMember(key, AGRIGENTO, 100, GeoUnit.KM)); + + assertThat(responses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(responses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List responsesWithParam = exec(commandObjects.georadiusByMember(key, AGRIGENTO, 100, GeoUnit.KM, param)); + + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(AGRIGENTO_LATITUDE, 0.001))); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(AGRIGENTO_LONGITUDE, 0.001))); + + List binaryResponses = exec(commandObjects.georadiusByMember(binaryKey, AGRIGENTO.getBytes(), 100, GeoUnit.KM)); + + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List binaryResponsesWithParam = exec(commandObjects.georadiusByMember(binaryKey, AGRIGENTO.getBytes(), 100, GeoUnit.KM, param)); + + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO.getBytes(), PALERMO.getBytes())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(AGRIGENTO_LATITUDE, 0.001))); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(AGRIGENTO_LONGITUDE, 0.001))); + } + + @Test + public void testGeoRadiusByMemberReadonly() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withCoord().withDist(); + + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(key, AGRIGENTO_LONGITUDE, AGRIGENTO_LATITUDE, AGRIGENTO)); + + List responses = exec(commandObjects.georadiusByMemberReadonly(key, AGRIGENTO, 100, GeoUnit.KM)); + + assertThat(responses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(responses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List responsesWithParam = exec(commandObjects.georadiusByMemberReadonly(key, AGRIGENTO, 100, GeoUnit.KM, param)); + + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(AGRIGENTO_LATITUDE, 0.001))); + assertThat(responsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(AGRIGENTO_LONGITUDE, 0.001))); + + List binaryResponses = exec(commandObjects.georadiusByMemberReadonly(binaryKey, AGRIGENTO.getBytes(), 100, GeoUnit.KM)); + + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO, PALERMO)); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponses.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(nullValue(), nullValue())); + + List binaryResponsesWithParam = exec(commandObjects.georadiusByMemberReadonly(binaryKey, AGRIGENTO.getBytes(), 100, GeoUnit.KM, param)); + + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getMember).collect(Collectors.toList()), + containsInAnyOrder(AGRIGENTO.getBytes(), PALERMO.getBytes())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getDistance).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).collect(Collectors.toList()), + containsInAnyOrder(notNullValue(), notNullValue())); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLatitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LATITUDE, 0.001), closeTo(AGRIGENTO_LATITUDE, 0.001))); + assertThat(binaryResponsesWithParam.stream().map(GeoRadiusResponse::getCoordinate).map(GeoCoordinate::getLongitude).collect(Collectors.toList()), + containsInAnyOrder(closeTo(PALERMO_LONGITUDE, 0.001), closeTo(AGRIGENTO_LONGITUDE, 0.001))); + } + + @Test + public void testGeoradiusStore() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + String destinationKey = "result"; + String binaryDestinationKey = "resultBinary"; + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().sortAscending(); + + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + + GeoRadiusStoreParam storeParam = GeoRadiusStoreParam.geoRadiusStoreParam().store(destinationKey); + + Long store = exec(commandObjects.georadiusStore(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, 200, GeoUnit.KM, param, storeParam)); + assertThat(store, equalTo(2L)); + + List destination = exec(commandObjects.zrange(destinationKey, 0, -1)); + assertThat(destination, containsInAnyOrder(PALERMO, CATANIA)); + + GeoRadiusStoreParam storeParamForBinary = GeoRadiusStoreParam.geoRadiusStoreParam().store(binaryDestinationKey); + + Long storeBinary = exec(commandObjects.georadiusStore(binaryKey, PALERMO_LONGITUDE, PALERMO_LATITUDE, 200, GeoUnit.KM, param, storeParamForBinary)); + assertThat(storeBinary, equalTo(2L)); + + destination = exec(commandObjects.zrange(binaryDestinationKey, 0, -1)); + assertThat(destination, containsInAnyOrder(PALERMO, CATANIA)); + } + + @Test + public void testGeoradiusByMemberStore() { + String key = "locations"; + byte[] binaryKey = key.getBytes(); + + String destinationKey = "result"; + String binaryDestinationKey = "resultBinary"; + + GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().sortAscending(); + + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + + GeoRadiusStoreParam storeParam = GeoRadiusStoreParam.geoRadiusStoreParam().store(destinationKey); + + Long store = exec(commandObjects.georadiusByMemberStore(key, PALERMO, 200, GeoUnit.KM, param, storeParam)); + assertThat(store, equalTo(2L)); + + List storedResults = exec(commandObjects.zrange(destinationKey, 0, -1)); + assertThat(storedResults, containsInAnyOrder(PALERMO, CATANIA)); + + GeoRadiusStoreParam storeParamForBinary = GeoRadiusStoreParam.geoRadiusStoreParam().store(binaryDestinationKey); + + Long storeBinary = exec(commandObjects.georadiusByMemberStore(binaryKey, PALERMO.getBytes(), 200, GeoUnit.KM, param, storeParamForBinary)); + assertThat(storeBinary, equalTo(2L)); + + storedResults = exec(commandObjects.zrange(binaryDestinationKey, 0, -1)); + assertThat(storedResults, containsInAnyOrder(PALERMO, CATANIA)); + } + + @Test + public void testGeosearch() { + String key = "locations"; + + GeoCoordinate palermoCoord = new GeoCoordinate(PALERMO_LONGITUDE, PALERMO_LATITUDE); + + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + + List resultsByMember = exec(commandObjects.geosearch(key, PALERMO, 200, GeoUnit.KM)); + + assertThat(resultsByMember.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsByCoord = exec(commandObjects.geosearch(key, palermoCoord, 200, GeoUnit.KM)); + + assertThat(resultsByCoord.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsByMemberBox = exec(commandObjects.geosearch(key, PALERMO, 200, 200, GeoUnit.KM)); + + assertThat(resultsByMemberBox.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO)); + + List resultsByCoordBox = exec(commandObjects.geosearch(key, palermoCoord, 200, 200, GeoUnit.KM)); + + assertThat(resultsByCoordBox.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO)); + + GeoSearchParam params = GeoSearchParam.geoSearchParam() + .byRadius(200, GeoUnit.KM).withCoord().withDist().fromMember(PALERMO); + + List resultsWithParams = exec(commandObjects.geosearch(key, params)); + + assertThat(resultsWithParams.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsInvalidKey = exec(commandObjects.geosearch("invalidKey", PALERMO, 100, GeoUnit.KM)); + + assertThat(resultsInvalidKey, empty()); + } + + @Test + public void testGeosearchBinary() { + byte[] key = "locations".getBytes(); + + GeoCoordinate palermoCoord = new GeoCoordinate(PALERMO_LONGITUDE, PALERMO_LATITUDE); + + exec(commandObjects.geoadd(key, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO.getBytes())); + exec(commandObjects.geoadd(key, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA.getBytes())); + + List resultsByMember = exec(commandObjects.geosearch(key, PALERMO.getBytes(), 200, GeoUnit.KM)); + + assertThat(resultsByMember.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsByCoord = exec(commandObjects.geosearch(key, palermoCoord, 200, GeoUnit.KM)); + + assertThat(resultsByCoord.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsByMemberBox = exec(commandObjects.geosearch(key, PALERMO.getBytes(), 200, 200, GeoUnit.KM)); + + assertThat(resultsByMemberBox.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO)); + + List resultsByCoordBox = exec(commandObjects.geosearch(key, palermoCoord, 200, 200, GeoUnit.KM)); + + assertThat(resultsByCoordBox.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO)); + + GeoSearchParam params = GeoSearchParam.geoSearchParam() + .byRadius(200, GeoUnit.KM).withCoord().withDist().fromMember(PALERMO); + + List resultsWithParams = exec(commandObjects.geosearch(key, params)); + + assertThat(resultsWithParams.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()), + containsInAnyOrder(PALERMO, CATANIA)); + + List resultsInvalidKey = exec(commandObjects.geosearch("invalidKey".getBytes(), PALERMO.getBytes(), 100, GeoUnit.KM)); + + assertThat(resultsInvalidKey, empty()); + } + + @Test + public void testGeosearchStore() { + String srcKey = "locations"; + String destKey = "locationsStore"; + + GeoCoordinate palermoCoord = new GeoCoordinate(PALERMO_LONGITUDE, PALERMO_LATITUDE); + + exec(commandObjects.geoadd(srcKey, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(srcKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + + Long storeByMember = exec(commandObjects.geosearchStore(destKey, srcKey, PALERMO, 200, GeoUnit.KM)); + assertThat(storeByMember, equalTo(2L)); + + List storedResultsByMember = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByMember, containsInAnyOrder(PALERMO, CATANIA)); + + // Reset + exec(commandObjects.del(destKey)); + + Long storeByCoord = exec(commandObjects.geosearchStore(destKey, srcKey, palermoCoord, 200, GeoUnit.KM)); + assertThat(storeByCoord, equalTo(2L)); + + List storedResultsByCoord = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByCoord, containsInAnyOrder(PALERMO, CATANIA)); + + exec(commandObjects.del(destKey)); + + Long storeByMemberBox = exec(commandObjects.geosearchStore(destKey, srcKey, PALERMO, 200, 200, GeoUnit.KM)); + assertThat(storeByMemberBox, equalTo(1L)); + + List storedResultsByMemberBox = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByMemberBox, containsInAnyOrder(PALERMO)); + + exec(commandObjects.del(destKey)); + + Long storeByCoordBox = exec(commandObjects.geosearchStore(destKey, srcKey, palermoCoord, 200, 200, GeoUnit.KM)); + assertThat(storeByCoordBox, equalTo(1L)); + + List storedResultsByCoordBox = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByCoordBox, containsInAnyOrder(PALERMO)); + + exec(commandObjects.del(destKey)); + + GeoSearchParam params = GeoSearchParam.geoSearchParam() + .byRadius(200, GeoUnit.KM).fromMember(PALERMO); + + Long storeWithParams = exec(commandObjects.geosearchStore(destKey, srcKey, params)); + assertThat(storeWithParams, equalTo(2L)); + + List storedResultsWithParams = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsWithParams, containsInAnyOrder(PALERMO, CATANIA)); + } + + @Test + public void testGeosearchStoreBinary() { + byte[] srcKey = "locations".getBytes(); + byte[] destKey = "locationsStore".getBytes(); + + GeoCoordinate palermoCoord = new GeoCoordinate(PALERMO_LONGITUDE, PALERMO_LATITUDE); + + exec(commandObjects.geoadd(srcKey, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO.getBytes())); + exec(commandObjects.geoadd(srcKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA.getBytes())); + + Long storeByMember = exec(commandObjects.geosearchStore(destKey, srcKey, PALERMO.getBytes(), 200, GeoUnit.KM)); + assertThat(storeByMember, equalTo(2L)); + + List storedResultsByMember = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByMember, containsInAnyOrder(PALERMO.getBytes(), CATANIA.getBytes())); + + // Reset + exec(commandObjects.del(destKey)); + + Long storeByCoord = exec(commandObjects.geosearchStore(destKey, srcKey, palermoCoord, 200, GeoUnit.KM)); + assertThat(storeByCoord, equalTo(2L)); + + List storedResultsByCoord = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByCoord, containsInAnyOrder(PALERMO.getBytes(), CATANIA.getBytes())); + + exec(commandObjects.del(destKey)); + + Long storeByMemberBox = exec(commandObjects.geosearchStore(destKey, srcKey, PALERMO.getBytes(), 200, 200, GeoUnit.KM)); + assertThat(storeByMemberBox, equalTo(1L)); + + List storedResultsByMemberBox = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByMemberBox, containsInAnyOrder(PALERMO.getBytes())); + + exec(commandObjects.del(destKey)); + + Long storeByCoordBox = exec(commandObjects.geosearchStore(destKey, srcKey, palermoCoord, 200, 200, GeoUnit.KM)); + assertThat(storeByCoordBox, equalTo(1L)); + + List storedResultsByCoordBox = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsByCoordBox, containsInAnyOrder(PALERMO.getBytes())); + + exec(commandObjects.del(destKey)); + + GeoSearchParam params = GeoSearchParam.geoSearchParam() + .byRadius(200, GeoUnit.KM).fromMember(PALERMO); + + Long storeWithParams = exec(commandObjects.geosearchStore(destKey, srcKey, params)); + assertThat(storeWithParams, equalTo(2L)); + + List storedResultsWithParams = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(storedResultsWithParams, containsInAnyOrder(PALERMO.getBytes(), CATANIA.getBytes())); + } + + @Test + public void testGeosearchStoreStoreDist() { + String srcKey = "locations"; + byte[] srcKeyBytes = srcKey.getBytes(); + + String destKey = "resultKey"; + byte[] destKeyBytes = destKey.getBytes(); + + exec(commandObjects.geoadd(srcKey, PALERMO_LONGITUDE, PALERMO_LATITUDE, PALERMO)); + exec(commandObjects.geoadd(srcKey, CATANIA_LONGITUDE, CATANIA_LATITUDE, CATANIA)); + exec(commandObjects.geoadd(srcKey, SYRACUSE_LONGITUDE, SYRACUSE_LATITUDE, SYRACUSE)); + + GeoSearchParam params = new GeoSearchParam() + .byRadius(100, GeoUnit.KM).fromLonLat(15, 37); + + Long store = exec(commandObjects.geosearchStoreStoreDist(destKey, srcKey, params)); + assertThat(store, equalTo(2L)); + + List dstContent = exec(commandObjects.zrange(destKey, 0, -1)); + assertThat(dstContent, containsInAnyOrder(CATANIA, SYRACUSE)); + + exec(commandObjects.del(destKey)); + + Long storeWithBytes = exec(commandObjects.geosearchStoreStoreDist(destKeyBytes, srcKeyBytes, params)); + assertThat(storeWithBytes, equalTo(2L)); + + List dstContentWithBytes = exec(commandObjects.zrange(destKeyBytes, 0, -1)); + assertThat(dstContentWithBytes, containsInAnyOrder(CATANIA.getBytes(), SYRACUSE.getBytes())); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java new file mode 100644 index 0000000000..b025b85440 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java @@ -0,0 +1,405 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.nullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; + +/** + * Tests related to Hash commands. + */ +public class CommandObjectsHashCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsHashCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testHashSetGet() { + String key = "hashKey"; + String field = "name"; + String value = "John"; + + String getInitial = exec(commandObjects.hget(key, field)); + assertThat(getInitial, nullValue()); + + Long set = exec(commandObjects.hset(key, field, value)); + assertThat(set, equalTo(1L)); + + String get = exec(commandObjects.hget(key, field)); + assertThat(get, equalTo(value)); + } + + @Test + public void testHashSetGetBinary() { + byte[] key = "hashKeyBytes".getBytes(); + byte[] field = "field".getBytes(); + byte[] value = "value".getBytes(); + + byte[] getInitial = exec(commandObjects.hget(key, field)); + assertThat(getInitial, nullValue()); + + Long set = exec(commandObjects.hset(key, field, value)); + assertThat(set, equalTo(1L)); + + byte[] get = exec(commandObjects.hget(key, field)); + assertThat(get, equalTo(value)); + } + + @Test + public void testHashBulkSet() { + String key = "hashKey"; + + Map hash = new HashMap<>(); + hash.put("field1", "value1"); + hash.put("field2", "value2"); + + Long set = exec(commandObjects.hset(key, hash)); + assertThat(set, equalTo((long) hash.size())); + + List mget = exec(commandObjects.hmget(key, "field1", "field2")); + assertThat(mget, contains("value1", "value2")); + } + + @Test + public void testHashBulkSetBinary() { + byte[] key = "hashKey".getBytes(); + + Map hash = new HashMap<>(); + hash.put("field1".getBytes(), "value1".getBytes()); + hash.put("field2".getBytes(), "value2".getBytes()); + + Long set = exec(commandObjects.hset(key, hash)); + assertThat(set, equalTo((long) hash.size())); + + List mget = exec(commandObjects.hmget(key, "field1".getBytes(), "field2".getBytes())); + assertThat(mget, contains("value1".getBytes(), "value2".getBytes())); + } + + @Test + public void testHashMsetMget() { + String key = "bulkHashKey"; + + Map hash = new HashMap<>(); + hash.put("field1", "value1"); + hash.put("field2", "value2"); + + String mset = exec(commandObjects.hmset(key, hash)); + assertThat(mset, equalTo("OK")); + + List mget = exec(commandObjects.hmget(key, "field1", "field2")); + assertThat(mget, contains("value1", "value2")); + } + + @Test + public void testHashMsetMgetBinary() { + byte[] key = "hashKey".getBytes(); + + Map hash = new HashMap<>(); + hash.put("field1".getBytes(), "value1".getBytes()); + hash.put("field2".getBytes(), "value2".getBytes()); + + String mset = exec(commandObjects.hmset(key, hash)); + assertThat(mset, equalTo("OK")); + + List mget = exec(commandObjects.hmget(key, "field1".getBytes(), "field2".getBytes())); + assertThat(mget, contains("value1".getBytes(), "value2".getBytes())); + } + + @Test + public void testHsetnx() { + String key = "hashKey"; + String field = "field"; + String value = "value"; + + String initialGet = exec(commandObjects.hget(key, field)); + assertThat(initialGet, nullValue()); + + Long initialSet = exec(commandObjects.hsetnx(key, field, value)); + assertThat(initialSet, equalTo(1L)); + + String get = exec(commandObjects.hget(key, field)); + assertThat(get, equalTo(value)); + + Long secondSet = exec(commandObjects.hsetnx(key, field, "newValue")); + assertThat(secondSet, equalTo(0L)); + + String secondGet = exec(commandObjects.hget(key, field)); + assertThat(secondGet, equalTo(value)); + } + + @Test + public void testHsetnxBinary() { + byte[] key = "hashKey".getBytes(); + byte[] field = "field".getBytes(); + byte[] value = "value".getBytes(); + + byte[] initialGet = exec(commandObjects.hget(key, field)); + assertThat(initialGet, nullValue()); + + Long set = exec(commandObjects.hsetnx(key, field, value)); + assertThat(set, equalTo(1L)); + + byte[] get = exec(commandObjects.hget(key, field)); + assertThat(get, equalTo(value)); + + Long secondSet = exec(commandObjects.hsetnx(key, field, "newValue".getBytes())); + assertThat(secondSet, equalTo(0L)); + + byte[] secondGet = exec(commandObjects.hget(key, field)); + assertThat(secondGet, equalTo(value)); + } + + @Test + public void testHincrBy() { + String key = "incrementHashKey"; + String field = "incrementField"; + + Long initialSet = exec(commandObjects.hset(key, field, "0")); + assertThat(initialSet, equalTo(1L)); + + String initialGet = exec(commandObjects.hget(key, field)); + assertThat(initialGet, equalTo("0")); + + Long incrByLong = exec(commandObjects.hincrBy(key, field, 10L)); + assertThat(incrByLong, equalTo(10L)); + + String getAfterIncrByLong = exec(commandObjects.hget(key, field)); + assertThat(getAfterIncrByLong, equalTo("10")); + + Double incrByFloat = exec(commandObjects.hincrByFloat(key, field, 2.5)); + assertThat(incrByFloat, equalTo(12.5)); + + String getAfterIncrByFloat = exec(commandObjects.hget(key, field)); + assertThat(getAfterIncrByFloat, equalTo("12.5")); + } + + @Test + public void testHincrByBinary() { + byte[] key = "key".getBytes(); + byte[] field = "field".getBytes(); + + Long initialSet = exec(commandObjects.hset(key, field, "0".getBytes())); + assertThat(initialSet, equalTo(1L)); + + byte[] initialGet = exec(commandObjects.hget(key, field)); + assertThat(initialGet, equalTo("0".getBytes())); + + Long incrByLong = exec(commandObjects.hincrBy(key, field, 10L)); + assertThat(incrByLong, equalTo(10L)); + + byte[] getAfterIncrByLong = exec(commandObjects.hget(key, field)); + assertThat(getAfterIncrByLong, equalTo("10".getBytes())); + + Double incrByDouble = exec(commandObjects.hincrByFloat(key, field, 2.5)); + assertThat(incrByDouble, equalTo(12.5)); + + byte[] getAfterIncrByDouble = exec(commandObjects.hget(key, field)); + assertThat(getAfterIncrByDouble, equalTo("12.5".getBytes())); + } + + @Test + public void testHashExistsDel() { + String key = "key"; + String field1 = "field1"; + String field2 = "field2"; + String value = "value"; + + exec(commandObjects.hset(key, field1, value)); + exec(commandObjects.hset(key, field2, value)); + + Boolean exists = exec(commandObjects.hexists(key, field1)); + assertThat(exists, equalTo(true)); + + Long len = exec(commandObjects.hlen(key)); + assertThat(len, equalTo(2L)); + + Long del = exec(commandObjects.hdel(key, field1)); + assertThat(del, equalTo(1L)); + + Boolean existsAfterDel = exec(commandObjects.hexists(key, field1)); + assertThat(existsAfterDel, equalTo(false)); + + Long lenAfterDel = exec(commandObjects.hlen(key)); + assertThat(lenAfterDel, equalTo(1L)); + } + + @Test + public void testHashExistsDelBinary() { + byte[] key = "key".getBytes(); + byte[] field1 = "field1".getBytes(); + byte[] field2 = "field2".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.hset(key, field1, value)); + exec(commandObjects.hset(key, field2, value)); + + Boolean exists = exec(commandObjects.hexists(key, field1)); + assertThat(exists, equalTo(true)); + + Long len = exec(commandObjects.hlen(key)); + assertThat(len, equalTo(2L)); + + Long del = exec(commandObjects.hdel(key, field1)); + assertThat(del, equalTo(1L)); + + Boolean existsAfterDel = exec(commandObjects.hexists(key, field1)); + assertThat(existsAfterDel, equalTo(false)); + + Long lenAfterDel = exec(commandObjects.hlen(key)); + assertThat(lenAfterDel, equalTo(1L)); + } + + @Test + public void testHashKeysValsGetAll() { + String key = "hashKey"; + byte[] keyBinary = key.getBytes(); + + String field1 = "field1"; + String field2 = "field2"; + String value1 = "value1"; + String value2 = "value2"; + + exec(commandObjects.hset(key, field1, value1)); + exec(commandObjects.hset(key, field2, value2)); + + Set keys = exec(commandObjects.hkeys(key)); + assertThat(keys, containsInAnyOrder(field1, field2)); + + List values = exec(commandObjects.hvals(key)); + assertThat(values, containsInAnyOrder(value1, value2)); + + Map hash = exec(commandObjects.hgetAll(key)); + assertThat(hash, allOf( + hasEntry(field1, value1), + hasEntry(field2, value2))); + + // binary + Set keysBinary = exec(commandObjects.hkeys(keyBinary)); + assertThat(keysBinary, containsInAnyOrder(field1.getBytes(), field2.getBytes())); + + List valuesBinary = exec(commandObjects.hvals(keyBinary)); + assertThat(valuesBinary, containsInAnyOrder(value1.getBytes(), value2.getBytes())); + + Map hashBinary = exec(commandObjects.hgetAll(keyBinary)); + assertThat(hashBinary, allOf( + hasEntry(field1.getBytes(), value1.getBytes()), + hasEntry(field2.getBytes(), value2.getBytes()))); + } + + @Test + public void testHashRandfield() { + String key = "testHash"; + byte[] bkey = key.getBytes(); + + exec(commandObjects.hset(key, "field1", "value1")); + exec(commandObjects.hset(key, "field2", "value2")); + + String singleField = exec(commandObjects.hrandfield(key)); + assertThat(singleField, anyOf(equalTo("field1"), equalTo("field2"))); + + List fields = exec(commandObjects.hrandfield(key, 2)); + assertThat(fields, containsInAnyOrder("field1", "field2")); + + List> fieldsWithValues = exec(commandObjects.hrandfieldWithValues(key, 2)); + + assertThat(fieldsWithValues, hasSize(2)); + fieldsWithValues.forEach(entry -> + assertThat(entry.getValue(), anyOf(equalTo("value1"), equalTo("value2")))); + + // binary + byte[] singleFieldBinary = exec(commandObjects.hrandfield(bkey)); + assertThat(singleFieldBinary, anyOf(equalTo("field1".getBytes()), equalTo("field2".getBytes()))); + + List fieldsBinary = exec(commandObjects.hrandfield(bkey, 2)); + assertThat(fieldsBinary, containsInAnyOrder("field1".getBytes(), "field2".getBytes())); + + List> fieldsWithValuesBinary = exec(commandObjects.hrandfieldWithValues(bkey, 2)); + + assertThat(fieldsWithValuesBinary, hasSize(2)); + fieldsWithValuesBinary.forEach(entry -> + assertThat(entry.getValue(), anyOf(equalTo("value1".getBytes()), equalTo("value2".getBytes())))); + } + + @Test + public void testHscan() { + String key = "testHashScan"; + byte[] bkey = key.getBytes(); + + exec(commandObjects.hset(key, "field1", "value1")); + exec(commandObjects.hset(key, "field2", "value2")); + + ScanParams params = new ScanParams().count(2); + + ScanResult> scanResult = exec(commandObjects.hscan(key, ScanParams.SCAN_POINTER_START, params)); + + assertThat(scanResult.getResult(), hasSize(lessThanOrEqualTo(2))); + + scanResult.getResult().forEach(entry -> + assertThat(entry.getKey(), anyOf(equalTo("field1"), equalTo("field2")))); + scanResult.getResult().forEach(entry -> + assertThat(entry.getValue(), anyOf(equalTo("value1"), equalTo("value2")))); + + ScanResult scanResultNoValues = exec(commandObjects.hscanNoValues(key, ScanParams.SCAN_POINTER_START, params)); + + assertThat(scanResultNoValues.getResult(), hasSize(lessThanOrEqualTo(2))); + + assertThat(scanResultNoValues.getResult(), + everyItem(anyOf(equalTo("field1"), equalTo("field2")))); + + // binary + ScanResult> bscanResult = exec(commandObjects.hscan(bkey, ScanParams.SCAN_POINTER_START_BINARY, params)); + + assertThat(bscanResult.getResult(), hasSize(lessThanOrEqualTo(2))); + + bscanResult.getResult().forEach(entry -> + assertThat(entry.getKey(), anyOf(equalTo("field1".getBytes()), equalTo("field2".getBytes())))); + bscanResult.getResult().forEach(entry -> + assertThat(entry.getValue(), anyOf(equalTo("value1".getBytes()), equalTo("value2".getBytes())))); + + ScanResult bscanResultNoValues = exec(commandObjects.hscanNoValues(bkey, ScanParams.SCAN_POINTER_START_BINARY, params)); + + assertThat(bscanResultNoValues.getResult(), hasSize(lessThanOrEqualTo(2))); + + assertThat(bscanResultNoValues.getResult(), + everyItem(anyOf(equalTo("field1".getBytes()), equalTo("field2".getBytes())))); + } + + @Test + public void testHashStrlen() { + String key = "testHashStrlen"; + byte[] bkey = key.getBytes(); + + exec(commandObjects.hset(key, "field1", "value1")); + + Long strlen = exec(commandObjects.hstrlen(key, "field1")); + assertThat(strlen, equalTo(6L)); + + Long strlenNonExistingField = exec(commandObjects.hstrlen(key, "nonExistingField")); + assertThat(strlenNonExistingField, equalTo(0L)); + + // binary + Long strlenBinary = exec(commandObjects.hstrlen(bkey, "field1".getBytes())); + assertThat(strlenBinary, equalTo(6L)); + + Long strlenNonExistingFieldBinary = exec(commandObjects.hstrlen(bkey, "nonExistingField".getBytes())); + assertThat(strlenNonExistingFieldBinary, equalTo(0L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHyperloglogCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHyperloglogCommandsTest.java new file mode 100644 index 0000000000..cdfe5aa7bd --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHyperloglogCommandsTest.java @@ -0,0 +1,94 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; + +/** + * Tests related to HyperLogLog commands. + */ +public class CommandObjectsHyperloglogCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsHyperloglogCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testPfaddAndCount() { + String key = "hyperloglogKey"; + + Long add = exec(commandObjects.pfadd(key, "element1", "element2", "element3")); + assertThat(add, equalTo(1L)); + + Long count = exec(commandObjects.pfcount(key)); + assertThat(count, greaterThanOrEqualTo(3L)); // approximate, expect at least 3 + + Long addNewElement = exec(commandObjects.pfadd(key, "element4")); + assertThat(addNewElement, equalTo(1L)); + + Long countWithNewElement = exec(commandObjects.pfcount(key)); + assertThat(countWithNewElement, greaterThan(count)); + } + + @Test + public void testPfaddAndCountBinary() { + byte[] key = "hyperloglogKey".getBytes(); + + Long add = exec(commandObjects.pfadd(key, "element1".getBytes(), "element2".getBytes(), "element3".getBytes())); + assertThat(add, equalTo(1L)); + + Long count = exec(commandObjects.pfcount(key)); + assertThat(count, greaterThanOrEqualTo(3L)); + } + + @Test + public void testPfmerge() { + String key1 = "hyperloglog1"; + String key2 = "hyperloglog2"; + + exec(commandObjects.pfadd(key1, "elementA", "elementB")); + exec(commandObjects.pfadd(key2, "elementC", "elementD")); + + String destKey = "mergedHyperloglog"; + byte[] destKeyBytes = "mergedHyperloglogBytes".getBytes(); + + String mergeResultWithString = exec(commandObjects.pfmerge(destKey, key1, key2)); + assertThat(mergeResultWithString, equalTo("OK")); + + Long countAfterMergeWithString = exec(commandObjects.pfcount(destKey)); + assertThat(countAfterMergeWithString, greaterThanOrEqualTo(4L)); + + // binary + String mergeResultWithBytes = exec(commandObjects.pfmerge(destKeyBytes, key1.getBytes(), key2.getBytes())); + assertThat(mergeResultWithBytes, equalTo("OK")); + + Long countAfterMergeWithBytes = exec(commandObjects.pfcount(destKeyBytes)); + assertThat(countAfterMergeWithBytes, greaterThanOrEqualTo(4L)); + } + + @Test + public void testPfcount() { + String key1 = "hyperloglogCount1"; + String key2 = "hyperloglogCount2"; + + exec(commandObjects.pfadd(key1, "element1", "element2", "element3")); + exec(commandObjects.pfadd(key2, "element4", "element5", "element6")); + + Long countForKey1 = exec(commandObjects.pfcount(key1)); + assertThat(countForKey1, greaterThanOrEqualTo(3L)); + + Long countForBothKeys = exec(commandObjects.pfcount(key1, key2)); + assertThat(countForBothKeys, greaterThanOrEqualTo(6L)); + + // binary + Long countForKey1Binary = exec(commandObjects.pfcount(key1.getBytes())); + assertThat(countForKey1Binary, greaterThanOrEqualTo(3L)); + + Long countForBothKeysBinary = exec(commandObjects.pfcount(key1.getBytes(), key2.getBytes())); + assertThat(countForBothKeysBinary, greaterThanOrEqualTo(6L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java new file mode 100644 index 0000000000..a416be2103 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsJsonCommandsTest.java @@ -0,0 +1,1434 @@ +package redis.clients.jedis.commands.commandobjects; + +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assume.assumeThat; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.json.JsonSetParams; +import redis.clients.jedis.json.Path; +import redis.clients.jedis.json.Path2; + +/** + * Tests related to JSON commands. + */ +public class CommandObjectsJsonCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsJsonCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testJsonSetAndJsonGet() { + String key = "jsonKey"; + + JSONObject person = new JSONObject(); + person.put("name", "John Doe"); + person.put("age", 30); + + String setRoot = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(getRoot, jsonEquals(new JSONArray().put(person))); + + JSONObject details = new JSONObject(); + details.put("city", "New York"); + + String setDeep = exec(commandObjects.jsonSet(key, new Path2("$.details"), details)); + assertThat(setDeep, equalTo("OK")); + + Object getDeep = exec(commandObjects.jsonGet(key, new Path2("$.details"))); + assertThat(getDeep, jsonEquals(new JSONArray().put(details))); + + Object getFull = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + person.put("details", details); + assertThat(getFull, jsonEquals(new JSONArray().put(person))); + } + + @Test + public void testJsonSetWithEscape() { + String key = "jsonKey"; + + Map book = new HashMap<>(); + book.put("title", "Learning JSON"); + + String setRoot = exec(commandObjects.jsonSetWithEscape(key, Path2.ROOT_PATH, book)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray().put(new JSONObject(book)); + assertThat(getRoot, jsonEquals(expected)); + } + + @Test + @Deprecated + public void testJsonSetJsonGetOldPath() { + String key = "jsonKey"; + + Map book = new HashMap<>(); + book.put("author", "Jane Doe"); + book.put("title", "Advanced JSON Techniques"); + + String setRoot = exec(commandObjects.jsonSet(key, Path.ROOT_PATH, book)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path.ROOT_PATH)); + assertThat(getRoot, instanceOf(Map.class)); + + @SuppressWarnings("unchecked") + Map getRootMap = (Map) getRoot; + assertThat(getRootMap, hasEntry("author", "Jane Doe")); + assertThat(getRootMap, hasEntry("title", "Advanced JSON Techniques")); + } + + @Test + @Deprecated + public void testJsonSetWithPlainString() { + String key = "jsonKey"; + String jsonString = "{\"name\":\"John\"}"; + + String setRoot = exec(commandObjects.jsonSetWithPlainString(key, Path.ROOT_PATH, jsonString)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path.ROOT_PATH)); + assertThat(getRoot, instanceOf(Map.class)); + + @SuppressWarnings("unchecked") + Map getRootMap = (Map) getRoot; + assertThat(getRootMap, hasEntry("name", "John")); + } + + @Test + public void testJsonSetWithParams() { + String key = "jsonKey"; + + JSONObject book = new JSONObject(); + book.put("author", "Jane Doe"); + book.put("title", "Advanced JSON Techniques"); + + JsonSetParams params = new JsonSetParams().nx(); + + String setRoot = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, book, params)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray().put(book); + assertThat(getRoot, jsonEquals(expected)); + } + + @Test + public void testJsonSetWithEscapeAndParams() { + String key = "jsonKey"; + + Map book = new HashMap<>(); + book.put("author", "John Smith"); + book.put("title", "JSON Escaping 101"); + + JsonSetParams params = new JsonSetParams().nx(); + + String setRoot = exec(commandObjects.jsonSetWithEscape(key, Path2.ROOT_PATH, book, params)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray().put(new JSONObject(book)); + assertThat(getRoot, jsonEquals(expected)); + } + + @Test + @Deprecated + public void testJsonSetOldPathWithParams() { + String key = "jsonKey"; + + Map user = new HashMap<>(); + user.put("username", "johndoe"); + user.put("accountType", "premium"); + + JsonSetParams params = new JsonSetParams().nx(); + + String setRoot = exec(commandObjects.jsonSet(key, Path.ROOT_PATH, user, params)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path.ROOT_PATH)); + assertThat(getRoot, instanceOf(Map.class)); + + @SuppressWarnings("unchecked") + Map readResultMap = (Map) getRoot; + assertThat(readResultMap, hasEntry("username", "johndoe")); + assertThat(readResultMap, hasEntry("accountType", "premium")); + } + + @Test + public void testJsonMerge() { + String key = "jsonKey"; + + JSONObject initialUser = new JSONObject(); + initialUser.put("name", "John Doe"); + initialUser.put("age", 30); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, initialUser)); + + JSONObject mergeUser = new JSONObject(); + mergeUser.put("occupation", "Software Developer"); + mergeUser.put("age", 31); // Assuming we're updating the age as well + + String mergeRoot = exec(commandObjects.jsonMerge(key, Path2.ROOT_PATH, mergeUser)); + assertThat(mergeRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(getRoot, notNullValue()); + + JSONObject expectedUser = new JSONObject(); + expectedUser.put("name", "John Doe"); + expectedUser.put("age", 31); + expectedUser.put("occupation", "Software Developer"); + + JSONArray expected = new JSONArray().put(expectedUser); + assertThat(getRoot, jsonEquals(expected)); + } + + @Test + @Deprecated + public void testJsonMergeOldPath() { + String key = "jsonKey"; + + Map initialUser = new HashMap<>(); + initialUser.put("name", "Jane Doe"); + + exec(commandObjects.jsonSet(key, Path.ROOT_PATH, initialUser)); + + Map mergeUser = new HashMap<>(); + mergeUser.put("occupation", "Data Scientist"); + mergeUser.put("name", "Jane Smith"); // update the name as well + + String mergeRoot = exec(commandObjects.jsonMerge(key, Path.ROOT_PATH, mergeUser)); + assertThat(mergeRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key, Path.ROOT_PATH)); + assertThat(getRoot, instanceOf(Map.class)); + + @SuppressWarnings("unchecked") + Map resultMap = (Map) getRoot; + assertThat(resultMap, hasEntry("name", "Jane Smith")); + assertThat(resultMap, hasEntry("occupation", "Data Scientist")); + } + + @Test + @Deprecated + public void testJsonGenericObjectResp2() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "user:1000"; + + Person person = new Person(); + person.setName("John Doe"); + person.setAge(30); + + String setRoot = exec(commandObjects.jsonSet(key, Path.ROOT_PATH, person)); + assertThat(setRoot, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key)); + assertThat(getRoot, instanceOf(Map.class)); + + @SuppressWarnings("unchecked") + Map resultMap = (Map) getRoot; + assertThat(resultMap, hasEntry("name", "John Doe")); + assertThat(resultMap, hasEntry("age", 30.0)); + } + + @Test + @Deprecated + public void testJsonGenericObjectResp3() { + assumeThat(protocol, equalTo(RedisProtocol.RESP3)); + + String key = "user:1000"; + + Person person = new Person("John Doe", 30); + + String setResult = exec(commandObjects.jsonSet(key, Path.ROOT_PATH, person)); + assertThat(setResult, equalTo("OK")); + + Object getRoot = exec(commandObjects.jsonGet(key)); + assertThat(getRoot, instanceOf(JSONArray.class)); + + JSONObject expectedPerson = new JSONObject(); + expectedPerson.put("name", "John Doe"); + expectedPerson.put("age", 30); + + JSONArray expected = new JSONArray().put(expectedPerson); + assertThat(getRoot, jsonEquals(expected)); + } + + @Test + @Deprecated + public void testJsonGetWithClass() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "user:2000"; + + String jsonObject = "{\"name\":\"Jane Doe\",\"age\":25}"; + + exec(commandObjects.jsonSetWithPlainString(key, Path.ROOT_PATH, jsonObject)); + + Person getRoot = exec(commandObjects.jsonGet(key, Person.class)); + + assertThat(getRoot.getName(), equalTo("Jane Doe")); + assertThat(getRoot.getAge(), equalTo(25)); + } + + @Test + public void testJsonMGet() { + String keyBob = "user:bob"; + String keyCharlie = "user:charlie"; + + JSONObject bob = new JSONObject(); + bob.put("name", "Bob"); + bob.put("age", 30); + + JSONObject charlie = new JSONObject(); + charlie.put("name", "Charlie"); + charlie.put("age", 25); + + String setBobRoot = exec(commandObjects.jsonSet(keyBob, Path2.ROOT_PATH, bob)); + assertThat(setBobRoot, equalTo("OK")); + + String setCharlieRoot = exec(commandObjects.jsonSet(keyCharlie, Path2.ROOT_PATH, charlie)); + assertThat(setCharlieRoot, equalTo("OK")); + + List getNames = exec(commandObjects.jsonMGet(Path2.of("name"), keyBob, keyCharlie)); + assertThat(getNames, contains( + jsonEquals(new JSONArray().put("Bob")), + jsonEquals(new JSONArray().put("Charlie")) + )); + + List getRoots = exec(commandObjects.jsonMGet(Path2.ROOT_PATH, keyBob, keyCharlie)); + assertThat(getRoots, contains( + jsonEquals(new JSONArray().put(bob)), + jsonEquals(new JSONArray().put(charlie)) + )); + } + + @Test + @Deprecated + public void testJsonMGetOldPath() { + String keyBob = "user:bob"; + String keyCharlie = "user:charlie"; + + JSONObject bob = new JSONObject(); + bob.put("name", "Bob"); + bob.put("age", 30); + + JSONObject charlie = new JSONObject(); + charlie.put("name", "Charlie"); + charlie.put("age", 25); + + String setBobRoot = exec(commandObjects.jsonSet(keyBob, Path2.ROOT_PATH, bob)); + assertThat(setBobRoot, equalTo("OK")); + + String setCharlieRoot = exec(commandObjects.jsonSet(keyCharlie, Path2.ROOT_PATH, charlie)); + assertThat(setCharlieRoot, equalTo("OK")); + + List getNamesTyped = exec(commandObjects.jsonMGet(Path.of("name"), String.class, keyBob, keyCharlie)); + assertThat(getNamesTyped, contains("Bob", "Charlie")); + + List getPersonsTyped = exec(commandObjects.jsonMGet(Path.ROOT_PATH, Person.class, keyBob, keyCharlie)); + assertThat(getPersonsTyped, contains( + new Person("Bob", 30), + new Person("Charlie", 25) + )); + } + + @Test + @Deprecated + public void testJsonGetAsPlainString() { + String key = "user:3000"; + + Person person = new Person("John Smith", 30); + + exec(commandObjects.jsonSet(key, Path.ROOT_PATH, person)); + + String getName = exec(commandObjects.jsonGetAsPlainString(key, Path.of(".name"))); + assertThat(getName, equalTo("\"John Smith\"")); + + String getRoot = exec(commandObjects.jsonGetAsPlainString(key, Path.ROOT_PATH)); + assertThat(getRoot, jsonEquals(person)); + } + + @Test + @Deprecated + public void testJsonGetWithPathAndClass() { + String key = "user:4000"; + + String jsonObject = "{\"person\":{\"name\":\"Alice Johnson\",\"age\":28}}"; + + String setRoot = exec(commandObjects.jsonSetWithPlainString(key, Path.ROOT_PATH, jsonObject)); + assertThat(setRoot, equalTo("OK")); + + Person getPerson = exec(commandObjects.jsonGet(key, Person.class, Path.of(".person"))); + assertThat(getPerson.getName(), equalTo("Alice Johnson")); + assertThat(getPerson.getAge(), equalTo(28)); + } + + @Test + public void testJsonDel() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long del = exec(commandObjects.jsonDel(key)); + assertThat(del, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(postCheck, nullValue()); + } + + @Test + public void testJsonDelPath() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long delAge = exec(commandObjects.jsonDel(key, Path2.of(".age"))); + assertThat(delAge, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonDelOldPath() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long delAge = exec(commandObjects.jsonDel(key, Path.of(".age"))); + assertThat(delAge, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonClear() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long clear = exec(commandObjects.jsonClear(key)); + assertThat(clear, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray().put(new JSONObject()); + assertThat(postCheck, jsonEquals(expected)); + } + + @Test + public void testJsonClearPath() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + person.put("occupations", new JSONArray().put("Data Scientist").put("Developer")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long clearOccupations = exec(commandObjects.jsonClear(key, Path2.of(".occupations"))); + assertThat(clearOccupations, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina"); + expected.put("age", 29); + expected.put("occupations", new JSONArray()); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonClearOldPath() { + String key = "user:11000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + person.put("occupations", new JSONArray().put("Data Scientist").put("Developer")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long clearOccupations = exec(commandObjects.jsonClear(key, Path.of(".occupations"))); + assertThat(clearOccupations, equalTo(1L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina"); + expected.put("age", 29); + expected.put("occupations", new JSONArray()); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonToggle() { + String key = "user:13000"; + + JSONObject item = new JSONObject(); + item.put("active", true); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(item))); + + List toggle = exec(commandObjects.jsonToggle(key, Path2.of(".active"))); + assertThat(toggle, contains(false)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("active", false); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonType() { + String key = "jsonKey"; + + JSONObject item = new JSONObject(); + item.put("active", true); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + + List> type = exec(commandObjects.jsonType(key, Path2.of(".active"))); + assertThat(type, contains(boolean.class)); + } + + @Test + @Deprecated + public void testJsonTypeOldPath() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "jsonKey"; + + JSONObject item = new JSONObject(); + item.put("active", true); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + + Class type = exec(commandObjects.jsonType(key, Path.of(".active"))); + assertThat(type, equalTo(boolean.class)); + } + + @Test + public void testJsonStrAppend() { + String key = "user:1000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + List strAppend = exec(commandObjects.jsonStrAppend(key, Path2.of(".name"), " Smith")); + assertThat(strAppend, contains(10L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina Smith"); + expected.put("age", 29); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonStrAppendOldPath() { + String key = "user:1000"; + + JSONObject person = new JSONObject(); + person.put("name", "Gina"); + person.put("age", 29); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, person)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(person))); + + Long strAppend = exec(commandObjects.jsonStrAppend(key, Path.of(".name"), " Smith")); + assertThat(strAppend, equalTo(10L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("name", "Gina Smith"); + expected.put("age", 29); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonStrAppendRootPath() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "user:1000"; + + String setRoot = exec(commandObjects.jsonSetWithPlainString(key, Path.ROOT_PATH, "\"John\"")); + assertThat(setRoot, equalTo("OK")); + + Object getBefore = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(getBefore, jsonEquals(new JSONArray().put("John"))); + + Long strAppend = exec(commandObjects.jsonStrAppend(key, " Doe")); + assertThat(strAppend, equalTo(8L)); + + Object getAfter = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(getAfter, jsonEquals(new JSONArray().put("John Doe"))); + } + + @Test + @Deprecated + public void testJsonStrLenRootPath() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "user:1001"; + + String setRoot = exec(commandObjects.jsonSetWithPlainString(key, Path.ROOT_PATH, "\"Hello World\"")); + assertThat(setRoot, equalTo("OK")); + + Long strLen = exec(commandObjects.jsonStrLen(key)); + assertThat(strLen, equalTo(11L)); // "Hello World" length + } + + @Test + public void testJsonStrLen() { + String key = "user:1002"; + + JSONObject item = new JSONObject(); + item.put("message", "Hello, Redis!"); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + assertThat(setResponse, equalTo("OK")); + + List strLenResponse = exec(commandObjects.jsonStrLen(key, Path2.of(".message"))); + assertThat(strLenResponse, contains(13L)); // "Hello, Redis!" length + } + + @Test + @Deprecated + public void testJsonStrLenOldPath() { + String key = "user:1003"; + + JSONObject item = new JSONObject(); + item.put("message", "Hello, Redis!"); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + assertThat(setResponse, equalTo("OK")); + + Long strLenResponse = exec(commandObjects.jsonStrLen(key, Path.of(".message"))); + assertThat(strLenResponse, equalTo(13L)); // "Hello, Redis!" length + } + + @Test + public void testJsonNumIncrBy() { + String key = "user:12000"; + + JSONObject item = new JSONObject(); + item.put("balance", 100); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, item)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(item))); + + Object numIncrBy = exec(commandObjects.jsonNumIncrBy(key, Path2.of("$.balance"), 50.0)); + assertThat(numIncrBy, jsonEquals(new JSONArray().put(150.0))); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject(); + expected.put("balance", 150.0); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrAppendWithEscape() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Elixir") + .put("Swift"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrAppend = exec(commandObjects.jsonArrAppendWithEscape( + key, Path2.ROOT_PATH, "Kotlin", "TypeScript")); + assertThat(arrAppend, contains(4L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put("Elixir") + .put("Swift") + .put("Kotlin") + .put("TypeScript"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrAppend() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Java") + .put("Python"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + JSONObject person = new JSONObject(); + person.put("name", "John"); + + List arrAppend = exec(commandObjects.jsonArrAppend(key, Path2.ROOT_PATH, + "\"C++\"", "\"JavaScript\"", person)); + assertThat(arrAppend, contains(5L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put("Java") + .put("Python") + .put("C++") + .put("JavaScript") + .put(person); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrAppendOldPath() { + String key = "json"; + + JSONArray data = new JSONArray() + .put(new JSONArray() + .put("Java") + .put("Python")) + .put(1); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Person person = new Person("John", 45); + + Long arrAppend = exec( + commandObjects.jsonArrAppend(key, Path.of(".[0]"), "Swift", "Go", person)); + assertThat(arrAppend, equalTo(5L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put(new JSONArray() + .put("Java") + .put("Python") + .put("Swift") + .put("Go") + .put(new JSONObject() + .put("name", "John") + .put("age", 45))) + .put(1); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrIndex() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Java") + .put("Python") + .put("Java"); // duplicate + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + List arrIndex = exec(commandObjects.jsonArrIndex(key, Path2.ROOT_PATH, "\"Java\"")); + assertThat(arrIndex, contains(0L)); + + List arrIndexNotFound = exec(commandObjects.jsonArrIndex(key, Path2.ROOT_PATH, "\"C++\"")); + assertThat(arrIndexNotFound, contains(-1L)); + } + + @Test + public void testJsonArrIndexWithEscape() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Java") + .put("Python") + .put("Java"); // duplicate + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + List arrIndex = exec(commandObjects.jsonArrIndexWithEscape(key, Path2.ROOT_PATH, "Java")); + assertThat(arrIndex, contains(0L)); + + List arrIndexNotFound = exec(commandObjects.jsonArrIndexWithEscape(key, Path2.ROOT_PATH, "Go")); + assertThat(arrIndexNotFound, contains(-1L)); + } + + @Test + @Deprecated + public void testJsonArrIndexDeprecated() { + String key = "json"; + + JSONArray data = new JSONArray() + .put(new JSONArray() + .put("Java") + .put("Python") + .put("Java")); // duplicate + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Long arrIndex = exec(commandObjects.jsonArrIndex(key, Path.of(".[0]"), "Java")); + assertThat(arrIndex, equalTo(0L)); + + Long arrIndexNotFound = exec(commandObjects.jsonArrIndex(key, Path.of(".[0]"), "Swift")); + assertThat(arrIndexNotFound, equalTo(-1L)); + } + + @Test + public void testJsonArrInsert() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Java") + .put("Python"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrInsert = exec( + commandObjects.jsonArrInsert(key, Path2.ROOT_PATH, 1, "\"C++\"")); + assertThat(arrInsert, contains(3L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put("Java") + .put("C++") + .put("Python"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrInsertWithEscape() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("Java") + .put("Python"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrInsert = exec(commandObjects.jsonArrInsertWithEscape(key, Path2.ROOT_PATH, 1, "Go")); + assertThat(arrInsert, contains(3L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put("Java") + .put("Go") + .put("Python"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrInsertOldPath() { + String key = "json"; + + JSONArray data = new JSONArray() + .put(1) + .put(new JSONArray() + .put("Scala") + .put("Kotlin")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Long arrInsert = exec(commandObjects.jsonArrInsert(key, Path.of(".[1]"), 1, "Swift")); + assertThat(arrInsert, equalTo(3L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put(1) + .put(new JSONArray() + .put("Scala") + .put("Swift") + .put("Kotlin")); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopRoot() { + String key = "json"; + + JSONArray data = new JSONArray() + .put("apple") + .put("banana") + .put("cherry"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Object arrPop = exec(commandObjects.jsonArrPop(key)); + assertThat(arrPop, equalTo("cherry")); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put("apple") + .put("banana"); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrPopWithPath2() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrPop = exec(commandObjects.jsonArrPop(key, Path2.of(".fruits"))); + assertThat(arrPop, contains("cherry")); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana")); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopOldPath() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Object arrPop = exec(commandObjects.jsonArrPop(key, Path.of(".fruits"))); + assertThat(arrPop, equalTo("cherry")); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana")); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopRootWithType() { + String key = "json"; + + JSONArray data = new JSONArray() + .put(1) + .put(2) + .put(3); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Integer arrPop = exec(commandObjects.jsonArrPop(key, Integer.class)); + assertThat(arrPop, equalTo(3)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONArray expected = new JSONArray() + .put(1) + .put(2); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopWithOldPathAndType() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(20) + .put(30)); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Integer arrPop = exec(commandObjects.jsonArrPop(key, Integer.class, Path.of(".numbers"))); + assertThat(arrPop, equalTo(30)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(20)); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopWithOldPathTypeAndIndex() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(20) + .put(30)); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Integer arrPop = exec(commandObjects.jsonArrPop(key, Integer.class, Path.of(".numbers"), 1)); + assertThat(arrPop, equalTo(20)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(30)); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrPopWithPathAndIndex() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(20) + .put(30)); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrPop = exec(commandObjects.jsonArrPop(key, Path2.of(".numbers"), 1)); + assertThat(arrPop, contains(20.0)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(30)); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrPopOldPathAndIndex() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(20) + .put(30)); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Object arrPop = exec(commandObjects.jsonArrPop(key, Path.of(".numbers"), 1)); + assertThat(arrPop, equalTo(20.0)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("numbers", new JSONArray() + .put(10) + .put(30)); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + public void testJsonArrTrimWithPath() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry") + .put("date") + .put("fig")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + List arrTrim = exec(commandObjects.jsonArrTrim(key, Path2.of(".fruits"), 1, 3)); + assertThat(arrTrim, contains(3L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("fruits", new JSONArray() + .put("banana") + .put("cherry") + .put("date")); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrTrimOldPath() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry") + .put("date") + .put("fig")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Object preCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + assertThat(preCheck, jsonEquals(new JSONArray().put(data))); + + Long arrTrim = exec(commandObjects.jsonArrTrim(key, Path.of(".fruits"), 1, 3)); + assertThat(arrTrim, equalTo(3L)); + + Object postCheck = exec(commandObjects.jsonGet(key, Path2.ROOT_PATH)); + + JSONObject expected = new JSONObject() + .put("fruits", new JSONArray() + .put("banana") + .put("cherry") + .put("date")); + assertThat(postCheck, jsonEquals(new JSONArray().put(expected))); + } + + @Test + @Deprecated + public void testJsonArrLenRoot() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "json"; + + JSONArray data = new JSONArray() + .put("apple") + .put("banana") + .put("cherry") + .put("date") + .put("fig"); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Long arrLen = exec(commandObjects.jsonArrLen(key)); + assertThat(arrLen, equalTo(5L)); + } + + @Test + public void testJsonArrLenWithPath() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry") + .put("date") + .put("fig")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + List arrLen = exec(commandObjects.jsonArrLen(key, Path2.of(".fruits"))); + assertThat(arrLen, contains(5L)); + } + + @Test + @Deprecated + public void testJsonArrLenOldPath() { + String key = "json"; + + JSONObject data = new JSONObject() + .put("fruits", new JSONArray() + .put("apple") + .put("banana") + .put("cherry") + .put("date") + .put("fig")); + + exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + + Long arrLen = exec(commandObjects.jsonArrLen(key, Path.of(".fruits"))); + assertThat(arrLen, equalTo(5L)); + } + + @Test + @Deprecated + public void testJsonObjLenRoot() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "json"; + + JSONObject data = new JSONObject(); + data.put("name", "John"); + data.put("age", 30); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + Long objLen = exec(commandObjects.jsonObjLen(key)); + assertThat(objLen, equalTo(2L)); // 2 keys: "name" and "age" + } + + @Test + @Deprecated + public void testJsonObjLenOldPath() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + Long objLen = exec(commandObjects.jsonObjLen(key, Path.of(".user"))); + assertThat(objLen, equalTo(2L)); + } + + @Test + public void testJsonObjLenWithPath2() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + List objLen = exec(commandObjects.jsonObjLen(key, Path2.of(".user"))); + assertThat(objLen, contains(2L)); + } + + @Test + @Deprecated + public void testJsonObjKeysRoot() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + + String key = "json"; + + JSONObject data = new JSONObject(); + data.put("name", "John"); + data.put("age", 30); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + List keys = exec(commandObjects.jsonObjKeys(key)); + assertThat(keys, containsInAnyOrder("name", "age")); + } + + @Test + @Deprecated + public void testJsonObjKeysOldPath() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + List keys = exec(commandObjects.jsonObjKeys(key, Path.of(".user"))); + assertThat(keys, containsInAnyOrder("name", "age")); + } + + @Test + public void testJsonObjKeysWithPath() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + List> keys = exec(commandObjects.jsonObjKeys(key, Path2.of(".user"))); + assertThat(keys, contains(containsInAnyOrder("name", "age"))); + } + + @Test + @Deprecated + public void testJsonDebugMemoryRoot() { + assumeThat(protocol, not(equalTo(RedisProtocol.RESP3))); + String key = "json"; + + JSONObject data = new JSONObject() + .put("name", "John") + .put("age", 30); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + Long memoryUsage = exec(commandObjects.jsonDebugMemory(key)); + assertThat(memoryUsage, notNullValue()); + assertThat(memoryUsage, greaterThan(0L)); + } + + @Test + @Deprecated + public void testJsonDebugMemoryOldPath() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + Long memoryUsage = exec(commandObjects.jsonDebugMemory(key, Path.of(".user"))); + assertThat(memoryUsage, notNullValue()); + assertThat(memoryUsage, greaterThan(0L)); + } + + @Test + public void testJsonDebugMemoryWithPath2() { + String key = "json"; + + JSONObject data = new JSONObject().put("user", + new JSONObject() + .put("name", "John") + .put("age", 30)); + + String setResponse = exec(commandObjects.jsonSet(key, Path2.ROOT_PATH, data)); + assertThat(setResponse, equalTo("OK")); + + List memoryUsages = exec(commandObjects.jsonDebugMemory(key, Path2.of(".user"))); + assertThat(memoryUsages, contains(greaterThan(0L))); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java new file mode 100644 index 0000000000..c7f84157d1 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java @@ -0,0 +1,663 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; + +import java.util.List; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.ListDirection; +import redis.clients.jedis.args.ListPosition; +import redis.clients.jedis.params.LPosParams; +import redis.clients.jedis.util.KeyValue; + +/** + * Tests related to List commands. + */ +public class CommandObjectsListCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsListCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testPushCommands() { + String key = "list"; + + Long rpush = exec(commandObjects.rpush(key, "hello", "world")); + assertThat(rpush, equalTo(2L)); + + Long lpush = exec(commandObjects.lpush(key, "hello", "world")); + assertThat(lpush, equalTo(4L)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains("world", "hello", "hello", "world")); + } + + @Test + public void testPushCommandsBinary() { + String keyStr = "list"; + byte[] key = keyStr.getBytes(); + + Long rpush = exec(commandObjects.rpush(key, "hello".getBytes(), "world".getBytes())); + assertThat(rpush, equalTo(2L)); + + Long lpush = exec(commandObjects.lpush(key, "hello".getBytes(), "world".getBytes())); + assertThat(lpush, equalTo(4L)); + + List lrange = exec(commandObjects.lrange(keyStr, 0, -1)); + assertThat(lrange, contains("world", "hello", "hello", "world")); + } + + @Test + public void testLlen() { + String key = "list"; + + Long initialLength = exec(commandObjects.llen(key)); + assertThat(initialLength, equalTo(0L)); + + exec(commandObjects.rpush(key, "value", "value")); + + Long llen = exec(commandObjects.llen(key)); + assertThat(llen, equalTo(2L)); + + Long llenBinary = exec(commandObjects.llen(key.getBytes())); + assertThat(llenBinary, equalTo(2L)); + } + + @Test + public void testLrange() { + String key = "list"; + String value1 = "first"; + String value2 = "second"; + String value3 = "third"; + + exec(commandObjects.rpush(key, value1, value2, value3)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains(value1, value2, value3)); + + List lrangeBinary = exec(commandObjects.lrange(key.getBytes(), 0, -1)); + assertThat(lrangeBinary, contains(value1.getBytes(), value2.getBytes(), value3.getBytes())); + + List partialRange = exec(commandObjects.lrange(key, 1, 2)); + assertThat(partialRange, contains(value2, value3)); + + List emptyRange = exec(commandObjects.lrange(key, 4, 5)); + assertThat(emptyRange, empty()); + } + + @Test + public void testLtrim() { + String key = "list"; + + exec(commandObjects.rpush(key, "one", "two", "three", "four")); + + String trim = exec(commandObjects.ltrim(key, 1, 2)); + assertThat(trim, equalTo("OK")); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains("two", "three")); + } + + @Test + public void testLtrimBinary() { + byte[] key = "list".getBytes(); + + exec(commandObjects.rpush(key, "one".getBytes(), "two".getBytes(), "three".getBytes(), "four".getBytes())); + + String trim = exec(commandObjects.ltrim(key, 1, 2)); + assertThat(trim, equalTo("OK")); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains("two".getBytes(), "three".getBytes())); + } + + @Test + public void testLindexCommands() { + String key = "list"; + + exec(commandObjects.rpush(key, "alpha", "beta", "gamma")); + + String lindex = exec(commandObjects.lindex(key, 1)); + assertThat(lindex, equalTo("beta")); + + byte[] lindexBinary = exec(commandObjects.lindex(key.getBytes(), 2)); + assertThat(lindexBinary, equalTo("gamma".getBytes())); + + String lindexOufOfRange = exec(commandObjects.lindex(key, 5)); + assertThat(lindexOufOfRange, nullValue()); + + byte[] lindexLastPositionBinary = exec(commandObjects.lindex(key.getBytes(), -1)); + assertThat(lindexLastPositionBinary, equalTo("gamma".getBytes())); + } + + @Test + public void testLset() { + String key = "list"; + String initialValue = "initial"; + String updatedValue = "updated"; + + exec(commandObjects.rpush(key, initialValue)); + + String lindexBefore = exec(commandObjects.lindex(key, 0)); + assertThat(lindexBefore, equalTo(initialValue)); + + String lset = exec(commandObjects.lset(key, 0, updatedValue)); + assertThat(lset, equalTo("OK")); + + String lindexAfter = exec(commandObjects.lindex(key, 0)); + assertThat(lindexAfter, equalTo(updatedValue)); + } + + @Test + public void testLsetBinary() { + byte[] keyBytes = "list".getBytes(); + String initialValue = "initial"; + String updatedValue = "updated"; + + exec(commandObjects.rpush(keyBytes, initialValue.getBytes())); + + byte[] lindexBefore = exec(commandObjects.lindex(keyBytes, 0)); + assertThat(lindexBefore, equalTo(initialValue.getBytes())); + + String lset = exec(commandObjects.lset(keyBytes, 0, updatedValue.getBytes())); + assertThat(lset, equalTo("OK")); + + byte[] lindexAfter = exec(commandObjects.lindex(keyBytes, 0)); + assertThat(lindexAfter, equalTo(updatedValue.getBytes())); + } + + @Test + public void testLrem() { + String key = "remList"; + + exec(commandObjects.rpush(key, "duplicate", "duplicate", "unique")); + + List lrangeInitial = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrangeInitial, contains("duplicate", "duplicate", "unique")); + + Long lrem = exec(commandObjects.lrem(key, 1, "duplicate")); + assertThat(lrem, equalTo(1L)); + + List lrangeAfterLremSingle = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrangeAfterLremSingle, contains("duplicate", "unique")); + + Long lremNonExistent = exec(commandObjects.lrem(key, 0, "nonexistent")); + assertThat(lremNonExistent, equalTo(0L)); + + List lrangeAfterLremNonExistent = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrangeAfterLremNonExistent, contains("duplicate", "unique")); + } + + @Test + public void testLremBinary() { + byte[] keyBytes = "remList".getBytes(); + + exec(commandObjects.rpush(keyBytes, "duplicate".getBytes(), "duplicate".getBytes(), "unique".getBytes())); + + List lrangeBefore = exec(commandObjects.lrange(keyBytes, 0, -1)); + assertThat(lrangeBefore, contains("duplicate".getBytes(), "duplicate".getBytes(), "unique".getBytes())); + + Long lremMultiple = exec(commandObjects.lrem(keyBytes, 0, "duplicate".getBytes())); + assertThat(lremMultiple, equalTo(2L)); + + List lrangeAfter = exec(commandObjects.lrange(keyBytes, 0, -1)); + assertThat(lrangeAfter, contains("unique".getBytes())); + } + + @Test + public void testPopCommands() { + String key = "popList"; + + exec(commandObjects.rpush(key, + "first", "second", "third", "first", "second", "third")); + + String lpop = exec(commandObjects.lpop(key)); + assertThat(lpop, equalTo("first")); + + String rpop = exec(commandObjects.rpop(key)); + assertThat(rpop, equalTo("third")); + + List lpopMultiple = exec(commandObjects.lpop(key, 2)); + assertThat(lpopMultiple, contains("second", "third")); + + List rpopMultiple = exec(commandObjects.rpop(key, 2)); + assertThat(rpopMultiple, contains("second", "first")); + } + + @Test + public void testPopCommandsBinary() { + byte[] key = "popList".getBytes(); + + exec(commandObjects.rpush(key, + "first".getBytes(), "second".getBytes(), "third".getBytes(), + "first".getBytes(), "second".getBytes(), "third".getBytes())); + + byte[] lpop = exec(commandObjects.lpop(key)); + assertThat(lpop, equalTo("first".getBytes())); + + byte[] rpop = exec(commandObjects.rpop(key)); + assertThat(rpop, equalTo("third".getBytes())); + + List lpopMultiple = exec(commandObjects.lpop(key, 2)); + assertThat(lpopMultiple, contains("second".getBytes(), "third".getBytes())); + + List rpopMultiple = exec(commandObjects.rpop(key, 2)); + assertThat(rpopMultiple, contains("second".getBytes(), "first".getBytes())); + } + + @Test + public void testLpos() { + String key = "list"; + String value = "target"; + String nonExistentValue = "ghost"; + + exec(commandObjects.rpush(key, "start", value, "middle", value, "end")); + + Long lposFirst = exec(commandObjects.lpos(key, value)); + assertThat(lposFirst, equalTo(1L)); + + Long lposFirstBinary = exec(commandObjects.lpos(key.getBytes(), value.getBytes())); + assertThat(lposFirstBinary, equalTo(1L)); + + LPosParams params = LPosParams.lPosParams().rank(-1); + Long lposLast = exec(commandObjects.lpos(key, value, params)); + assertThat(lposLast, equalTo(3L)); + + Long lposLastBinary = exec(commandObjects.lpos(key.getBytes(), value.getBytes(), params)); + assertThat(lposLastBinary, equalTo(3L)); + + List lposMultiple = exec(commandObjects.lpos(key, value, params, 2)); + assertThat(lposMultiple, contains(3L, 1L)); + + List lposMultipleBinary = exec(commandObjects.lpos(key.getBytes(), value.getBytes(), params, 2)); + assertThat(lposMultipleBinary, contains(3L, 1L)); + + Long lposNonExistent = exec(commandObjects.lpos(key, nonExistentValue)); + assertThat(lposNonExistent, nullValue()); + + Long lposNonExistentBinary = exec(commandObjects.lpos(key.getBytes(), nonExistentValue.getBytes())); + assertThat(lposNonExistentBinary, nullValue()); + } + + @Test + public void testLinsert() { + String key = "insertList"; + String pivot = "pivot"; + String valueBefore = "beforePivot"; + String valueAfter = "afterPivot"; + + exec(commandObjects.rpush(key, pivot)); + + Long linsertBefore = exec(commandObjects.linsert(key, ListPosition.BEFORE, pivot, valueBefore)); + assertThat(linsertBefore, equalTo(2L)); + + Long linsertAfter = exec(commandObjects.linsert(key, ListPosition.AFTER, pivot, valueAfter)); + assertThat(linsertAfter, equalTo(3L)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains(valueBefore, pivot, valueAfter)); + } + + @Test + public void testLinsertBinary() { + byte[] key = "insertList".getBytes(); + byte[] pivot = "pivot".getBytes(); + byte[] valueBefore = "valueBefore".getBytes(); + byte[] valueAfter = "valueAfter".getBytes(); + + exec(commandObjects.rpush(key, pivot)); + + Long linsertBefore = exec(commandObjects.linsert(key, ListPosition.BEFORE, pivot, valueBefore)); + assertThat(linsertBefore, equalTo(2L)); + + Long linsertAfter = exec(commandObjects.linsert(key, ListPosition.AFTER, pivot, valueAfter)); + assertThat(linsertAfter, equalTo(3L)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains(valueBefore, pivot, valueAfter)); + } + + @Test + public void testPushxCommands() { + String key = "pushxList"; + String value1 = "first"; + String value2 = "second"; + + Long lpushxInitial = exec(commandObjects.lpushx(key, value1)); + assertThat(lpushxInitial, equalTo(0L)); + + Long rpushxInitial = exec(commandObjects.rpushx(key, value1)); + assertThat(rpushxInitial, equalTo(0L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + + exec(commandObjects.lpush(key, "init")); + + Long lpushx = exec(commandObjects.lpushx(key, value1, value2)); + assertThat(lpushx, equalTo(3L)); // new size returned + + Long rpushx = exec(commandObjects.rpushx(key, value1, value2)); + assertThat(rpushx, equalTo(5L)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains(value2, value1, "init", value1, value2)); + } + + @Test + public void testPushxCommandsBinary() { + byte[] key = "pushxList".getBytes(); + byte[] value1 = "first".getBytes(); + byte[] value2 = "second".getBytes(); + + Long lpushxInitial = exec(commandObjects.lpushx(key, value1)); + assertThat(lpushxInitial, equalTo(0L)); + + Long rpushxInitial = exec(commandObjects.rpushx(key, value1)); + assertThat(rpushxInitial, equalTo(0L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + + exec(commandObjects.lpush(key, "init".getBytes())); + + Long lpushx = exec(commandObjects.lpushx(key, value1, value2)); + assertThat(lpushx, equalTo(3L)); + + Long rpushx = exec(commandObjects.rpushx(key, value1, value2)); + assertThat(rpushx, equalTo(5L)); + + List lrange = exec(commandObjects.lrange(key, 0, -1)); + assertThat(lrange, contains(value2, value1, "init".getBytes(), value1, value2)); + } + + @Test + public void testBlpop() { + String key1 = "list1"; + String key2 = "list2"; + String value1 = "value1"; + String value2 = "value2"; + + exec(commandObjects.lpush(key1, value1)); + + List blpop = exec(commandObjects.blpop(1, key1)); + assertThat(blpop, contains(key1, value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + List blpopMultiple = exec(commandObjects.blpop(1, key1, key2)); + assertThat(blpopMultiple, anyOf(contains(key1, value1), contains(key2, value2))); + + exec(commandObjects.lpush(key1, value1)); + + KeyValue blpopDoubleTimeout = exec(commandObjects.blpop(1.0, key1)); + assertThat(blpopDoubleTimeout.getKey(), equalTo(key1)); + assertThat(blpopDoubleTimeout.getValue(), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + KeyValue blpopDoubleTimeoutMultiple = exec(commandObjects.blpop(1.0, key1, key2)); + assertThat(blpopDoubleTimeoutMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blpopDoubleTimeoutMultiple.getValue(), anyOf(equalTo(value1), equalTo(value2))); + } + + @Test + public void testBlpopBinary() { + byte[] key1 = "list1".getBytes(); + byte[] key2 = "list2".getBytes(); + byte[] value1 = "value1".getBytes(); + byte[] value2 = "value2".getBytes(); + + exec(commandObjects.lpush(key1, value1)); + + List blpop = exec(commandObjects.blpop(1, key1)); + assertThat(blpop.get(0), equalTo(key1)); + assertThat(blpop.get(1), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + List blpopMultiple = exec(commandObjects.blpop(1, key1, key2)); + assertThat(blpopMultiple, anyOf(contains(key1, value1), contains(key2, value2))); + + exec(commandObjects.lpush(key1, value1)); + + KeyValue blpopDoubleTimeout = exec(commandObjects.blpop(1.0, key1)); + assertThat(blpopDoubleTimeout.getKey(), equalTo(key1)); + assertThat(blpopDoubleTimeout.getValue(), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + KeyValue blpopDoubleTimeoutMultiple = exec(commandObjects.blpop(1.0, key1, key2)); + assertThat(blpopDoubleTimeoutMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blpopDoubleTimeoutMultiple.getValue(), anyOf(equalTo(value1), equalTo(value2))); + } + + @Test + public void testBrpop() { + String key1 = "list1"; + String key2 = "list2"; + String value1 = "value1"; + String value2 = "value2"; + + exec(commandObjects.lpush(key1, value1)); + + List brpop = exec(commandObjects.brpop(1, key1)); + assertThat(brpop, contains(key1, value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + List brpopMultiple = exec(commandObjects.brpop(1, key1, key2)); + assertThat(brpopMultiple, anyOf(contains(key1, value1), contains(key2, value2))); + + exec(commandObjects.lpush(key1, value1)); + + KeyValue brpopDoubleTimeout = exec(commandObjects.brpop(1.0, key1)); + assertThat(brpopDoubleTimeout.getKey(), equalTo(key1)); + assertThat(brpopDoubleTimeout.getValue(), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + KeyValue brpopDoubleTimeoutMultiple = exec(commandObjects.brpop(1.0, key1, key2)); + assertThat(brpopDoubleTimeoutMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(brpopDoubleTimeoutMultiple.getValue(), anyOf(equalTo(value1), equalTo(value2))); + } + + @Test + public void testBrpopBinary() { + byte[] key1 = "list1".getBytes(); + byte[] key2 = "list2".getBytes(); + byte[] value1 = "value1".getBytes(); + byte[] value2 = "value2".getBytes(); + + exec(commandObjects.lpush(key1, value1)); + + List brpop = exec(commandObjects.brpop(1, key1)); + assertThat(brpop.get(0), equalTo(key1)); + assertThat(brpop.get(1), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + List brpopMultiple = exec(commandObjects.brpop(1, key1, key2)); + assertThat(brpopMultiple, anyOf(contains(key1, value1), contains(key2, value2))); + + exec(commandObjects.lpush(key1, value1)); + + KeyValue brpopDoubleTimeout = exec(commandObjects.brpop(1.0, key1)); + assertThat(brpopDoubleTimeout.getKey(), equalTo(key1)); + assertThat(brpopDoubleTimeout.getValue(), equalTo(value1)); + + exec(commandObjects.lpush(key1, value1)); + exec(commandObjects.lpush(key2, value2)); + + KeyValue brpopDoubleTimeoutMultiple = exec(commandObjects.brpop(1.0, key1, key2)); + assertThat(brpopDoubleTimeoutMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(brpopDoubleTimeoutMultiple.getValue(), anyOf(equalTo(value1), equalTo(value2))); + } + + @Test + public void testRpoplpushAndBrpoplpush() { + String srcKey = "sourceList"; + String dstKey = "destinationList"; + String value1 = "value1"; + String value2 = "value2"; + + String noResult = exec(commandObjects.rpoplpush(srcKey, dstKey)); + assertThat(noResult, nullValue()); + + exec(commandObjects.lpush(srcKey, value1)); + + String result = exec(commandObjects.rpoplpush(srcKey, dstKey)); + assertThat(result, equalTo(value1)); + + List dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(value1)); + + exec(commandObjects.lpush(srcKey, value2)); + + String bResult = exec(commandObjects.brpoplpush(srcKey, dstKey, 1)); + assertThat(bResult, equalTo(value2)); + + dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(value2, value1)); + } + + @Test + public void testRpoplpushAndBrpoplpushBinary() { + byte[] srcKey = "sourceList".getBytes(); + byte[] dstKey = "destinationList".getBytes(); + byte[] value1 = "value1".getBytes(); + byte[] value2 = "value2".getBytes(); + + exec(commandObjects.lpush(srcKey, value1)); + + byte[] result = exec(commandObjects.rpoplpush(srcKey, dstKey)); + assertThat(result, equalTo(value1)); + + List dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(equalTo(value1))); + + exec(commandObjects.lpush(srcKey, value2)); + + byte[] bResult = exec(commandObjects.brpoplpush(srcKey, dstKey, 1)); + assertThat(bResult, equalTo(value2)); + + dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(equalTo(value2), equalTo(value1))); + } + + @Test + public void testLmoveAndBlmove() { + String srcKey = "sourceList"; + String dstKey = "destinationList"; + String value1 = "value1"; + String value2 = "value2"; + + exec(commandObjects.lpush(srcKey, value1)); + + String result = exec(commandObjects.lmove(srcKey, dstKey, ListDirection.LEFT, ListDirection.RIGHT)); + assertThat(result, equalTo(value1)); + + List dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(value1)); + + exec(commandObjects.lpush(srcKey, value2)); + + String bResult = exec(commandObjects.blmove(srcKey, dstKey, ListDirection.LEFT, ListDirection.LEFT, 1.0)); + assertThat(bResult, equalTo(value2)); + + dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(value2, value1)); + } + + @Test + public void testLmoveAndBlmoveBinary() { + byte[] srcKey = "sourceList".getBytes(); + byte[] dstKey = "destinationList".getBytes(); + byte[] value1 = "value1".getBytes(); + byte[] value2 = "value2".getBytes(); + + exec(commandObjects.lpush(srcKey, value1)); + + byte[] result = exec(commandObjects.lmove(srcKey, dstKey, ListDirection.LEFT, ListDirection.RIGHT)); + assertThat(result, equalTo(value1)); + + List dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList.get(0), equalTo(value1)); + + exec(commandObjects.lpush(srcKey, value2)); + + byte[] bResult = exec(commandObjects.blmove(srcKey, dstKey, ListDirection.LEFT, ListDirection.LEFT, 1.0)); + assertThat(bResult, equalTo(value2)); + + dstList = exec(commandObjects.lrange(dstKey, 0, -1)); + assertThat(dstList, contains(equalTo(value2), equalTo(value1))); + } + + @Test + public void testLmpopAndBlmpop() { + String key1 = "list1"; + String key2 = "list2"; + String value1 = "value1"; + String value2 = "value2"; + + exec(commandObjects.lpush(key1, value1, value1, value1, value1, value1, value1)); + exec(commandObjects.lpush(key2, value2, value2, value2, value2, value2, value2)); + + KeyValue> lmpop = exec(commandObjects.lmpop(ListDirection.LEFT, key1, key2)); + assertThat(lmpop.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(lmpop.getValue(), anyOf(contains(value1), contains(value2))); + + KeyValue> lmpopMultiple = exec(commandObjects.lmpop(ListDirection.LEFT, 2, key1, key2)); + assertThat(lmpopMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(lmpopMultiple.getValue(), anyOf(contains(value1, value1), contains(value2, value2))); + + KeyValue> blmpop = exec(commandObjects.blmpop(1.0, ListDirection.LEFT, key1, key2)); + assertThat(blmpop.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blmpop.getValue(), anyOf(contains(value1), contains(value2))); + + KeyValue> blmpopMultiple = exec(commandObjects.blmpop(1.0, ListDirection.LEFT, 2, key1, key2)); + assertThat(blmpopMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blmpopMultiple.getValue(), anyOf(contains(value1, value1), contains(value2, value2))); + } + + @Test + public void testLmpopAndBlmpopBinary() { + byte[] key1 = "list1".getBytes(); + byte[] key2 = "list2".getBytes(); + byte[] value1 = "value1".getBytes(); + byte[] value2 = "value2".getBytes(); + + exec(commandObjects.lpush(key1, value1, value1, value1, value1, value1, value1)); + exec(commandObjects.lpush(key2, value2, value2, value2, value2, value2, value2)); + + KeyValue> lmpop = exec(commandObjects.lmpop(ListDirection.LEFT, key1, key2)); + assertThat(lmpop.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(lmpop.getValue(), anyOf(contains(equalTo(value1)), contains(equalTo(value2)))); + + KeyValue> lmpopMultiple = exec(commandObjects.lmpop(ListDirection.LEFT, 2, key1, key2)); + assertThat(lmpopMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(lmpopMultiple.getValue(), anyOf(contains(equalTo(value1), equalTo(value1)), contains(equalTo(value2), equalTo(value2)))); + + KeyValue> blmpop = exec(commandObjects.blmpop(1.0, ListDirection.LEFT, key1, key2)); + assertThat(blmpop.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blmpop.getValue(), anyOf(contains(equalTo(value1)), contains(equalTo(value2)))); + + KeyValue> blmpopMultiple = exec(commandObjects.blmpop(1.0, ListDirection.LEFT, 2, key1, key2)); + assertThat(blmpopMultiple.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(blmpopMultiple.getValue(), anyOf(contains(equalTo(value1), equalTo(value1)), contains(equalTo(value2), equalTo(value2)))); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java new file mode 100644 index 0000000000..3bac716fa4 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsModulesTestBase.java @@ -0,0 +1,19 @@ +package redis.clients.jedis.commands.commandobjects; + +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.Protocol; +import redis.clients.jedis.RedisProtocol; + +/** + * Base class for tests that need a Redis Stack server. + */ +public abstract class CommandObjectsModulesTestBase extends CommandObjectsTestBase { + + private static final String address = + System.getProperty("modulesDocker", Protocol.DEFAULT_HOST + ':' + 6479); + + public CommandObjectsModulesTestBase(RedisProtocol protocol) { + super(protocol, HostAndPort.from(address), null); + } + +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java new file mode 100644 index 0000000000..7b6c1feae9 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java @@ -0,0 +1,815 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThrows; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.FlushMode; +import redis.clients.jedis.args.FunctionRestorePolicy; +import redis.clients.jedis.exceptions.JedisException; +import redis.clients.jedis.resps.FunctionStats; +import redis.clients.jedis.resps.LibraryInfo; + +/** + * Tests related to Scripting commands. + */ +public class CommandObjectsScriptingCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsScriptingCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testEvalWithOnlyScript() { + String set = exec(commandObjects.set("foo", "bar")); + assertThat(set, equalTo("OK")); + + String script = "return redis.call('get', 'foo')"; + + Object eval = exec(commandObjects.eval(script)); + assertThat(eval, equalTo("bar")); + + Object evalBinary = exec(commandObjects.eval(script.getBytes())); + assertThat(evalBinary, equalTo("bar".getBytes())); + + // eval with incorrect script + assertThrows(JedisException.class, + () -> exec(commandObjects.eval("return x"))); + } + + @Test + public void testEvalWithScriptAndSampleKey() { + String set = exec(commandObjects.set("foo", "bar")); + assertThat(set, equalTo("OK")); + + String script = "return redis.call('get', 'foo');"; + + Object eval = exec(commandObjects.eval(script, "sampleKey")); + assertThat(eval, equalTo("bar")); + + Object evalBinary = exec(commandObjects.eval(script.getBytes(), "sampleKey".getBytes())); + assertThat(evalBinary, equalTo("bar".getBytes())); + } + + @Test + public void testEvalWithScriptKeyCountAndParams() { + exec(commandObjects.set("key1", "value1")); + exec(commandObjects.set("key2", "value2")); + + // Script to get values of two keys and compare them + String script = "if redis.call('get', KEYS[1]) == ARGV[1] and redis.call('get', KEYS[2]) == ARGV[2] then return 'true' else return 'false' end"; + + Object evalTrue = exec(commandObjects.eval( + script, 2, "key1", "key2", "value1", "value2")); + + assertThat(evalTrue, equalTo("true")); + + Object evalTrueBinary = exec(commandObjects.eval( + script.getBytes(), 2, "key1".getBytes(), "key2".getBytes(), "value1".getBytes(), "value2".getBytes())); + + assertThat(evalTrueBinary, equalTo("true".getBytes())); + + Object evalFalse = exec(commandObjects.eval( + script, 2, "key1", "key2", "value1", "value3")); + + assertThat(evalFalse, equalTo("false")); + + Object evalFalseBinary = exec(commandObjects.eval( + script.getBytes(), 2, "key1".getBytes(), "key2".getBytes(), "value1".getBytes(), "value3".getBytes())); + + assertThat(evalFalseBinary, equalTo("false".getBytes())); + + // Incorrect number of keys specified + assertThrows(JedisException.class, + () -> exec(commandObjects.eval(script, 1, "key1", "value1", "value2"))); + } + + @Test + public void testEvalWithScriptKeysAndArgsList() { + exec(commandObjects.hset("fruits", "apples", "5")); + exec(commandObjects.hset("fruits", "bananas", "3")); + exec(commandObjects.hset("fruits", "oranges", "4")); + + // Script to sum the values for the fruits provided as args. The hash name is provided as key. + // The sum is written to a string value whose name is also provided as keys. + String script = "local sum = 0\n" + + "for i, fruitKey in ipairs(ARGV) do\n" + + " local value = redis.call('HGET', KEYS[1], fruitKey)\n" + + " if value then\n" + + " sum = sum + tonumber(value)\n" + + " end\n" + + "end\n" + + "redis.call('SET', KEYS[2], sum)\n" + + "return sum"; + + String initialTotal = exec(commandObjects.get("total")); + assertThat(initialTotal, nullValue()); + + Object eval = exec(commandObjects.eval(script, + Arrays.asList("fruits", "total"), Arrays.asList("apples", "bananas", "oranges"))); + + assertThat(eval, equalTo(12L)); + + String totalAfterEval = exec(commandObjects.get("total")); + assertThat(totalAfterEval, equalTo("12")); + + // reset + assertThat(exec(commandObjects.del("total")), equalTo(1L)); + + // binary + String initialTotalBinary = exec(commandObjects.get("total")); + assertThat(initialTotalBinary, nullValue()); + + Object evalBinary = exec(commandObjects.eval(script.getBytes(), + Arrays.asList("fruits".getBytes(), "total".getBytes()), Arrays.asList("apples".getBytes(), "bananas".getBytes(), "oranges".getBytes()))); + + assertThat(evalBinary, equalTo(12L)); + + String totalAfterEvalBinary = exec(commandObjects.get("total")); + assertThat(totalAfterEvalBinary, equalTo("12")); + } + + @Test + public void testEvalReadonlyWithScriptKeysAndArgsList() { + exec(commandObjects.set("readonlyKey1", "readonlyValue1")); + exec(commandObjects.set("readonlyKey2", "readonlyValue2")); + + // Script to retrieve values for provided keys, concatenates + String script = "return redis.call('get', KEYS[1]) .. redis.call('get', KEYS[2])"; + + Object eval = exec(commandObjects.evalReadonly( + script, Arrays.asList("readonlyKey1", "readonlyKey2"), Collections.emptyList())); + + assertThat(eval, equalTo("readonlyValue1readonlyValue2")); + + Object evalBinary = exec(commandObjects.evalReadonly( + script.getBytes(), Arrays.asList("readonlyKey1".getBytes(), "readonlyKey2".getBytes()), Collections.emptyList())); + + assertThat(evalBinary, equalTo("readonlyValue1readonlyValue2".getBytes())); + } + + @Test + public void testEvalshaWithSha1() { + String script = "return 42"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + Object eval = exec(commandObjects.evalsha(sha1)); + assertThat(eval, equalTo(42L)); + + Object evalBinary = exec(commandObjects.evalsha(sha1.getBytes())); + assertThat(evalBinary, equalTo(42L)); + + // incorrect SHA1 hash + assertThrows(JedisException.class, + () -> exec(commandObjects.evalsha("incorrectSha1"))); + } + + @Test + public void testEvalshaWithSha1AndSampleKey() { + String script = "return redis.call('get', 'foo')"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + exec(commandObjects.set("foo", "bar")); + + Object eval = exec(commandObjects.evalsha(sha1, "sampleKey")); + + assertThat(eval, equalTo("bar")); + + Object evalBinary = exec(commandObjects.evalsha(sha1.getBytes(), "sampleKey".getBytes())); + + assertThat(evalBinary, equalTo("bar".getBytes())); + } + + @Test + public void testEvalWithScriptKeyCountAndParamsSha() { + exec(commandObjects.set("key1", "value1")); + exec(commandObjects.set("key2", "value2")); + + // Script to get values of two keys and compare them with expected values + String script = "if redis.call('get', KEYS[1]) == ARGV[1] and redis.call('get', KEYS[2]) == ARGV[2] then return 'true' else return 'false' end"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + Object evalTrue = exec(commandObjects.evalsha( + sha1, 2, "key1", "key2", "value1", "value2")); + + assertThat(evalTrue, equalTo("true")); + + Object evalTrueBinary = exec(commandObjects.evalsha( + sha1.getBytes(), 2, "key1".getBytes(), "key2".getBytes(), "value1".getBytes(), "value2".getBytes())); + + assertThat(evalTrueBinary, equalTo("true".getBytes())); + + Object evalFalse = exec(commandObjects.evalsha( + sha1, 2, "key1", "key2", "value1", "value3")); + + assertThat(evalFalse, equalTo("false")); + + Object evalFalseBinary = exec(commandObjects.evalsha( + sha1.getBytes(), 2, "key1".getBytes(), "key2".getBytes(), "value1".getBytes(), "value3".getBytes())); + + assertThat(evalFalseBinary, equalTo("false".getBytes())); + + // Incorrect number of keys + assertThrows(JedisException.class, + () -> exec(commandObjects.evalsha(sha1, 1, "key1", "value1", "value2"))); + } + + @Test + public void testEvalWithScriptKeysAndArgsListSha() { + exec(commandObjects.hset("fruits", "apples", "5")); + exec(commandObjects.hset("fruits", "bananas", "3")); + exec(commandObjects.hset("fruits", "oranges", "4")); + + // Sums the values for given fruits, stores the result, and returns it + String script = "local sum = 0\n" + + "for i, fruitKey in ipairs(ARGV) do\n" + + " local value = redis.call('HGET', KEYS[1], fruitKey)\n" + + " if value then\n" + + " sum = sum + tonumber(value)\n" + + " end\n" + + "end\n" + + "redis.call('SET', KEYS[2], sum)\n" + + "return sum"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + String initialTotal = exec(commandObjects.get("total")); + assertThat(initialTotal, nullValue()); + + Object eval = exec(commandObjects.evalsha( + sha1, Arrays.asList("fruits", "total"), Arrays.asList("apples", "bananas", "oranges"))); + + assertThat(eval, equalTo(12L)); + + String totalAfterEval = exec(commandObjects.get("total")); + assertThat(totalAfterEval, equalTo("12")); + + // reset + assertThat(exec(commandObjects.del("total")), equalTo(1L)); + + // binary + String initialTotalBinary = exec(commandObjects.get("total")); + assertThat(initialTotalBinary, nullValue()); + + Object evalBinary = exec(commandObjects.evalsha( + sha1.getBytes(), + Arrays.asList("fruits".getBytes(), "total".getBytes()), + Arrays.asList("apples".getBytes(), "bananas".getBytes(), "oranges".getBytes()))); + + assertThat(evalBinary, equalTo(12L)); + + String totalAfterEvalBinary = exec(commandObjects.get("total")); + assertThat(totalAfterEvalBinary, equalTo("12")); + } + + @Test + public void testEvalReadonlyWithScriptKeysAndArgsListSha() { + exec(commandObjects.set("readonlyKey1", "readonlyValue1")); + exec(commandObjects.set("readonlyKey2", "readonlyValue2")); + + // Script to retrieve values for provided keys, concatenated + String script = "return redis.call('get', KEYS[1]) .. redis.call('get', KEYS[2])"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + Object eval = exec(commandObjects.evalshaReadonly( + sha1, + Arrays.asList("readonlyKey1", "readonlyKey2"), + Collections.emptyList())); + + assertThat(eval, equalTo("readonlyValue1readonlyValue2")); + + Object evalBinary = exec(commandObjects.evalshaReadonly( + sha1.getBytes(), + Arrays.asList("readonlyKey1".getBytes(), "readonlyKey2".getBytes()), + Collections.emptyList())); + + assertThat(evalBinary, equalTo("readonlyValue1readonlyValue2".getBytes())); + } + + @Test + public void testScriptExists() { + String script = "return 'test script'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List exists = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + + assertThat(exists, contains(true)); + + // Load another script to test with multiple SHA1 hashes + String anotherScript = "return 'another test script'"; + String anotherSha1 = exec(commandObjects.scriptLoad(anotherScript)); + assertThat(anotherSha1, notNullValue()); + + String nonExistingSha1 = "nonexistentsha1"; + + List existsMultiple = exec(commandObjects.scriptExists( + "sampleKey", sha1, anotherSha1, nonExistingSha1)); + + assertThat(existsMultiple, contains(true, true, false)); + + List existsMultipleBinary = exec(commandObjects.scriptExists( + "sampleKey".getBytes(), sha1.getBytes(), anotherSha1.getBytes(), nonExistingSha1.getBytes())); + + assertThat(existsMultipleBinary, contains(true, true, false)); + } + + @Test + public void testScriptLoadAndRun() { + String script = "return 'Hello, Redis!'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + Object scriptResponse1 = exec(commandObjects.evalsha(sha1)); + assertThat(scriptResponse1, equalTo("Hello, Redis!")); + } + + @Test + public void testScriptLoadAndRunSampleKey() { + String anotherScript = "return redis.call('get', 'testKey')"; + + String sampleKey = "testKey"; + exec(commandObjects.set(sampleKey, "sampleValue")); // Set a value for the sampleKey + + String anotherSha1 = exec(commandObjects.scriptLoad(anotherScript, sampleKey)); + assertThat(anotherSha1, notNullValue()); + + Object scriptResponse2 = exec(commandObjects.evalsha(anotherSha1, sampleKey)); + assertThat(scriptResponse2, equalTo("sampleValue")); + } + + @Test + public void testScriptLoadAndRunSampleKeyBinary() { + String anotherScript = "return redis.call('get', 'testKey')"; + + String sampleKey = "testKey"; + exec(commandObjects.set(sampleKey, "sampleValue")); // Set a value for the sampleKey + + byte[] anotherSha1 = exec(commandObjects.scriptLoad(anotherScript.getBytes(), sampleKey.getBytes())); + assertThat(anotherSha1, notNullValue()); + + Object scriptResponse2 = exec(commandObjects.evalsha(anotherSha1, sampleKey.getBytes())); + assertThat(scriptResponse2, equalTo("sampleValue".getBytes())); + } + + @Test + public void testScriptFlush() { + String script = "return 'test script flush'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List existsBefore = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsBefore, contains(true)); + + String flush = exec(commandObjects.scriptFlush()); + assertThat(flush, equalTo("OK")); + + List existsAfter = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsAfter, contains(false)); + } + + @Test + public void testScriptFlushSampleKeyAndMode() { + String script = "return 'test script flush'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List existsBefore = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsBefore, contains(true)); + + String flush = exec(commandObjects.scriptFlush("anyKey", FlushMode.SYNC)); + assertThat(flush, equalTo("OK")); + + List existsAfter = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsAfter, contains(false)); + } + + @Test + public void testScriptFlushSampleKey() { + String script = "return 'test script flush'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List existsBefore = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsBefore, contains(true)); + + String flush = exec(commandObjects.scriptFlush("anyKey")); + assertThat(flush, equalTo("OK")); + + List existsAfter = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsAfter, contains(false)); + } + + @Test + public void testScriptFlushBinary() { + String script = "return 'test script flush'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List existsBefore = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsBefore, contains(true)); + + String flush = exec(commandObjects.scriptFlush("anyKey".getBytes())); + assertThat(flush, equalTo("OK")); + + List existsAfter = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsAfter, contains(false)); + } + + @Test + public void testScriptFlushSampleKeyAndModeBinary() { + String script = "return 'test script flush'"; + String sha1 = exec(commandObjects.scriptLoad(script)); + assertThat(sha1, notNullValue()); + + List existsBefore = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsBefore, contains(true)); + + String flush = exec(commandObjects.scriptFlush("anyKey".getBytes(), FlushMode.SYNC)); + assertThat(flush, equalTo("OK")); + + List existsAfter = exec(commandObjects.scriptExists(Collections.singletonList(sha1))); + assertThat(existsAfter, contains(false)); + } + + @Test + public void testScriptKill() { + JedisException e = assertThrows(JedisException.class, + () -> exec(commandObjects.scriptKill())); + assertThat(e.getMessage(), containsString("No scripts in execution right now.")); + + e = assertThrows(JedisException.class, + () -> exec(commandObjects.scriptKill("anyKey"))); + assertThat(e.getMessage(), containsString("No scripts in execution right now.")); + + e = assertThrows(JedisException.class, + () -> exec(commandObjects.scriptKill("anyKey".getBytes()))); + assertThat(e.getMessage(), containsString("No scripts in execution right now.")); + } + + @Test + public void testSumValuesFunction() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args)\n" + + "local sum = 0\n" + + "for _, key in ipairs(keys) do\n" + + "local val = redis.call('GET', key)\n" + + "if val then sum = sum + tonumber(val) end\n" + + "end\n" + + "redis.call('SET', 'total', sum)\n" + + "return sum\n" + + "end)"; + String functionLoad = exec(commandObjects.functionLoad(luaScript)); + assertThat(functionLoad, equalTo("mylib")); + + exec(commandObjects.set("key1", "10")); + exec(commandObjects.set("key2", "20")); + exec(commandObjects.set("key3", "30")); + + String initialTotal = exec(commandObjects.get("total")); + assertThat(initialTotal, nullValue()); + + Object fcall = exec(commandObjects.fcall( + "sumValues", + Arrays.asList("key1", "key2", "key3"), + new ArrayList<>())); + + assertThat(fcall, equalTo(60L)); + + String totalAfterFcall = exec(commandObjects.get("total")); + assertThat(totalAfterFcall, equalTo("60")); + + // reset + exec(commandObjects.del("total")); + + String totalAfterRest = exec(commandObjects.get("total")); + assertThat(totalAfterRest, nullValue()); + + Object fcallBinary = exec(commandObjects.fcall( + "sumValues".getBytes(), + Arrays.asList("key1".getBytes(), "key2".getBytes(), "key3".getBytes()), + new ArrayList<>())); + + assertThat(fcallBinary, equalTo(60L)); + + String totalAfterFcallBinary = exec(commandObjects.get("total")); + assertThat(totalAfterFcallBinary, equalTo("60")); + } + + @Test + public void testSumValuesFunctionReadonly() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function{function_name='sumValues', callback=function(keys, args)\n" + + "local sum = 0\n" + + "for _, key in ipairs(keys) do\n" + + "local val = redis.call('GET', key)\n" + + "if val then sum = sum + tonumber(val) end\n" + + "end\n" + + "return sum\n" + + "end, flags={'no-writes'}}"; + String functionLoad = exec(commandObjects.functionLoad(luaScript)); + assertThat(functionLoad, equalTo("mylib")); + + exec(commandObjects.set("key1", "10")); + exec(commandObjects.set("key2", "20")); + exec(commandObjects.set("key3", "30")); + + Object fcall = exec(commandObjects.fcallReadonly( + "sumValues", + Arrays.asList("key1", "key2", "key3"), + new ArrayList<>())); + + assertThat(fcall, equalTo(60L)); + + Object fcallBinary = exec(commandObjects.fcallReadonly( + "sumValues".getBytes(), + Arrays.asList("key1".getBytes(), "key2".getBytes(), "key3".getBytes()), + new ArrayList<>())); + + assertThat(fcallBinary, equalTo(60L)); + } + + @Test + public void testFunctionDeletion() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List listResponse = exec(commandObjects.functionList()); + + assertThat(listResponse, hasSize(1)); + assertThat(listResponse.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(listResponse.get(0).getFunctions(), hasSize(1)); + assertThat(listResponse.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + + String delete = exec(commandObjects.functionDelete(libraryName)); + assertThat(delete, equalTo("OK")); + + listResponse = exec(commandObjects.functionList()); + assertThat(listResponse, empty()); + } + + @Test + public void testFunctionDeletionBinary() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List listResponse = exec(commandObjects.functionList()); + + assertThat(listResponse, hasSize(1)); + assertThat(listResponse.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(listResponse.get(0).getFunctions(), hasSize(1)); + assertThat(listResponse.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + + String deleteBinary = exec(commandObjects.functionDelete(libraryName.getBytes())); + assertThat(deleteBinary, equalTo("OK")); + + listResponse = exec(commandObjects.functionList()); + assertThat(listResponse, empty()); + } + + @Test + public void testFunctionListing() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List list = exec(commandObjects.functionList()); + + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + assertThat(list.get(0).getLibraryCode(), nullValue()); + + List listBinary = exec(commandObjects.functionListBinary()); + + assertThat(listBinary, hasSize(1)); + + List listLibrary = exec(commandObjects.functionList(libraryName)); + + assertThat(listLibrary, hasSize(1)); + assertThat(listLibrary.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(listLibrary.get(0).getFunctions(), hasSize(1)); + assertThat(listLibrary.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + assertThat(listLibrary.get(0).getLibraryCode(), nullValue()); + + List listLibraryBinary = exec(commandObjects.functionList(libraryName.getBytes())); + + assertThat(listLibraryBinary, hasSize(1)); + + List listWithCode = exec(commandObjects.functionListWithCode()); + + assertThat(listWithCode, hasSize(1)); + assertThat(listWithCode.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(listWithCode.get(0).getFunctions(), hasSize(1)); + assertThat(listWithCode.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + assertThat(listWithCode.get(0).getLibraryCode(), notNullValue()); + + List listWithCodeBinary = exec(commandObjects.functionListWithCodeBinary()); + + assertThat(listWithCodeBinary, hasSize(1)); + + List listWithCodeLibrary = exec(commandObjects.functionListWithCode(libraryName)); + + assertThat(listWithCodeLibrary, hasSize(1)); + assertThat(listWithCodeLibrary.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(listWithCodeLibrary.get(0).getFunctions(), hasSize(1)); + assertThat(listWithCodeLibrary.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + assertThat(listWithCodeLibrary.get(0).getLibraryCode(), notNullValue()); + + List listWithCodeLibraryBinary = exec(commandObjects.functionListWithCode(libraryName.getBytes())); + + assertThat(listWithCodeLibraryBinary, hasSize(1)); + } + + @Test + public void testFunctionReload() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('dummy', function(keys, args) return 42 end)"; + String loadResult = exec(commandObjects.functionLoad(luaScript)); + assertThat(loadResult, equalTo("mylib")); + + Object result = exec(commandObjects.fcall( + "dummy".getBytes(), new ArrayList<>(), new ArrayList<>())); + assertThat(result, equalTo(42L)); + + String luaScriptChanged = "#!lua name=mylib\n" + + "redis.register_function('dummy', function(keys, args) return 52 end)"; + String replaceResult = exec(commandObjects.functionLoadReplace(luaScriptChanged)); + assertThat(replaceResult, equalTo("mylib")); + + Object resultAfter = exec(commandObjects.fcall( + "dummy".getBytes(), new ArrayList<>(), new ArrayList<>())); + assertThat(resultAfter, equalTo(52L)); + } + + @Test + public void testFunctionReloadBinary() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('dummy', function(keys, args) return 42 end)"; + String loadResult = exec(commandObjects.functionLoad(luaScript.getBytes())); + assertThat(loadResult, equalTo("mylib")); + + Object result = exec(commandObjects.fcall(( + "dummy").getBytes(), new ArrayList<>(), new ArrayList<>())); + assertThat(result, equalTo(42L)); + + String luaScriptChanged = "#!lua name=mylib\n" + + "redis.register_function('dummy', function(keys, args) return 52 end)"; + String replaceResult = exec(commandObjects.functionLoadReplace(luaScriptChanged.getBytes())); + assertThat(replaceResult, equalTo("mylib")); + + Object resultAfter = exec(commandObjects.fcall( + "dummy".getBytes(), new ArrayList<>(), new ArrayList<>())); + assertThat(resultAfter, equalTo(52L)); + } + + @Test + public void testFunctionStats() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('dummy', function(keys, args) return 42 end)"; + String loadResult = exec(commandObjects.functionLoad(luaScript)); + assertThat(loadResult, equalTo("mylib")); + + for (int i = 0; i < 5; i++) { + Object result = exec(commandObjects.fcall( + "dummy".getBytes(), new ArrayList<>(), new ArrayList<>())); + assertThat(result, equalTo(42L)); + } + + FunctionStats stats = exec(commandObjects.functionStats()); + + assertThat(stats, notNullValue()); + assertThat(stats.getEngines(), hasKey("LUA")); + Map luaStats = stats.getEngines().get("LUA"); + assertThat(luaStats, hasEntry("libraries_count", 1L)); + assertThat(luaStats, hasEntry("functions_count", 1L)); + + Object statsBinary = exec(commandObjects.functionStatsBinary()); + + assertThat(statsBinary, notNullValue()); + } + + @Test + public void testFunctionDumpFlushRestore() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List list = exec(commandObjects.functionList()); + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + + byte[] dump = exec(commandObjects.functionDump()); + assertThat(dump, notNullValue()); + + String flush = exec(commandObjects.functionFlush()); + assertThat(flush, equalTo("OK")); + + list = exec(commandObjects.functionList()); + assertThat(list, empty()); + + String restore = exec(commandObjects.functionRestore(dump)); + assertThat(restore, equalTo("OK")); + + list = exec(commandObjects.functionList()); + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + } + + @Test + public void testFunctionDumpFlushRestoreWithPolicy() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List list = exec(commandObjects.functionList()); + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + + byte[] dump = exec(commandObjects.functionDump()); + assertThat(dump, notNullValue()); + + String flush = exec(commandObjects.functionFlush()); + assertThat(flush, equalTo("OK")); + + list = exec(commandObjects.functionList()); + assertThat(list, empty()); + + String restore = exec(commandObjects.functionRestore(dump, FunctionRestorePolicy.REPLACE)); + assertThat(restore, equalTo("OK")); + + list = exec(commandObjects.functionList()); + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + } + + @Test + public void testFunctionFlushWithMode() { + String luaScript = "#!lua name=mylib\n" + + "redis.register_function('sumValues', function(keys, args) return 42 end)"; + exec(commandObjects.functionLoad(luaScript)); + + String libraryName = "mylib"; + + List list = exec(commandObjects.functionList()); + + assertThat(list, hasSize(1)); + assertThat(list.get(0).getLibraryName(), equalTo(libraryName)); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0), hasEntry("name", "sumValues")); + + String flush = exec(commandObjects.functionFlush(FlushMode.SYNC)); + assertThat(flush, equalTo("OK")); + + list = exec(commandObjects.functionList()); + assertThat(list, empty()); + } + + @Test + public void testFunctionKill() { + JedisException e = assertThrows(JedisException.class, + () -> exec(commandObjects.functionKill())); + assertThat(e.getMessage(), containsString("No scripts in execution right now")); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java new file mode 100644 index 0000000000..d1b1eaacaa --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java @@ -0,0 +1,255 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.emptyOrNullString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.json.JSONObject; +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.SortingOrder; +import redis.clients.jedis.json.Path2; +import redis.clients.jedis.search.Document; +import redis.clients.jedis.search.FTSearchParams; +import redis.clients.jedis.search.IndexDefinition; +import redis.clients.jedis.search.IndexOptions; +import redis.clients.jedis.search.Query; +import redis.clients.jedis.search.Schema; +import redis.clients.jedis.search.SearchResult; +import redis.clients.jedis.search.aggr.AggregationBuilder; +import redis.clients.jedis.search.aggr.AggregationResult; +import redis.clients.jedis.search.aggr.Reducers; + +/** + * Tests related to Search and query commands. + */ +public class CommandObjectsSearchAndQueryCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsSearchAndQueryCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testFtSearchHash() { + String indexName = "booksIndex"; + + IndexDefinition indexDefinition = + new IndexDefinition(IndexDefinition.Type.HASH).setPrefixes("books:"); + + IndexOptions indexOptions = IndexOptions.defaultOptions().setDefinition(indexDefinition); + + Schema schema = new Schema() + .addField(new Schema.Field("title", Schema.FieldType.TEXT)) + .addField(new Schema.Field("price", Schema.FieldType.NUMERIC)); + + String create = exec(commandObjects.ftCreate(indexName, indexOptions, schema)); + assertThat(create, equalTo("OK")); + + // Set individual fields. + String book1000 = "books:1000"; + + Long hset = exec(commandObjects.hsetObject(book1000, "title", "Redis in Action")); + assertThat(hset, equalTo(1L)); + + hset = exec(commandObjects.hsetObject(book1000, "price", 17.99)); + assertThat(hset, equalTo(1L)); + + hset = exec(commandObjects.hsetObject(book1000, "author", "John Doe")); + assertThat(hset, equalTo(1L)); + + // Set multiple fields. + Map hash = new HashMap<>(); + hash.put("title", "Redis Essentials"); + hash.put("price", 19.99); + hash.put("author", "Jane Doe"); + String book1200 = "books:1200"; + + Long hsetMultiple = exec(commandObjects.hsetObject(book1200, hash)); + assertThat(hsetMultiple, equalTo(3L)); + + // Text search. + SearchResult search = exec(commandObjects.ftSearch(indexName, "Action")); + + assertThat(search.getTotalResults(), equalTo(1L)); + assertThat(search.getDocuments(), hasSize(1)); + + Document document = search.getDocuments().get(0); + assertThat(document.getId(), equalTo(book1000)); + assertThat(document.get("title"), equalTo("Redis in Action")); + assertThat(document.get("price"), equalTo("17.99")); + assertThat(document.get("author"), equalTo("John Doe")); + + // Price range search. + SearchResult searchByPrice = exec(commandObjects.ftSearch(indexName, "@price:[19 +inf]")); + + assertThat(searchByPrice.getTotalResults(), equalTo(1L)); + assertThat(searchByPrice.getDocuments(), hasSize(1)); + + Document documentByPrice = searchByPrice.getDocuments().get(0); + assertThat(documentByPrice.getId(), equalTo(book1200)); + assertThat(documentByPrice.get("title"), equalTo("Redis Essentials")); + assertThat(documentByPrice.get("price"), equalTo("19.99")); + assertThat(documentByPrice.get("author"), equalTo("Jane Doe")); + + // Price range search with sorting. + FTSearchParams ftSearchParams = new FTSearchParams().sortBy("price", SortingOrder.DESC); + SearchResult searchByPriceWithParams = exec(commandObjects.ftSearch(indexName, "@price:[10 20]", ftSearchParams)); + + assertThat(searchByPriceWithParams.getTotalResults(), equalTo(2L)); + assertThat(searchByPriceWithParams.getDocuments(), hasSize(2)); + assertThat(searchByPriceWithParams.getDocuments().stream().map(Document::getId).collect(Collectors.toList()), + contains(book1200, book1000)); + + Query query = new Query() + .addFilter(new Query.NumericFilter("price", 19.0, 20.0)) + .returnFields("price", "title"); + SearchResult searchByPriceWithQuery = exec(commandObjects.ftSearch(indexName, query)); + + assertThat(searchByPriceWithQuery.getTotalResults(), equalTo(1L)); + assertThat(searchByPriceWithQuery.getDocuments(), hasSize(1)); + + Document documentByPriceWithQuery = searchByPriceWithQuery.getDocuments().get(0); + assertThat(documentByPriceWithQuery.getId(), equalTo(book1200)); + assertThat(documentByPriceWithQuery.get("title"), equalTo("Redis Essentials")); + assertThat(documentByPriceWithQuery.get("price"), equalTo("19.99")); + assertThat(documentByPriceWithQuery.get("author"), nullValue()); + } + + @Test + public void testFtSearchJson() { + String indexName = "testIndex"; + + IndexDefinition indexDefinition = new IndexDefinition(IndexDefinition.Type.JSON) + .setPrefixes("books:"); + + IndexOptions indexOptions = IndexOptions.defaultOptions().setDefinition(indexDefinition); + + Schema schema = new Schema() + .addField(new Schema.Field("$.title", Schema.FieldType.TEXT)) + .addField(new Schema.Field("$.price", Schema.FieldType.NUMERIC)); + + String create = exec(commandObjects.ftCreate(indexName, indexOptions, schema)); + assertThat(create, equalTo("OK")); + + Map hash = new HashMap<>(); + hash.put("title", "Redis in Action"); + hash.put("price", 17.99); + hash.put("author", "John Doe"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, new JSONObject(hash))); + assertThat(jsonSet, equalTo("OK")); + + Map hash2 = new HashMap<>(); + hash2.put("title", "Redis Essentials"); + hash2.put("price", 19.99); + hash2.put("author", "Jane Doe"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, new JSONObject(hash2))); + assertThat(jsonSet2, equalTo("OK")); + + SearchResult searchResult = exec(commandObjects.ftSearch(indexName, "Action")); + + assertThat(searchResult.getTotalResults(), equalTo(1L)); + assertThat(searchResult.getDocuments(), hasSize(1)); + + Document document = searchResult.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + assertThat(document.get("$"), equalTo("{\"title\":\"Redis in Action\",\"price\":17.99,\"author\":\"John Doe\"}")); + } + + @Test + public void testFtExplain() { + String indexName = "booksIndex"; + + IndexDefinition indexDefinition = new IndexDefinition(IndexDefinition.Type.HASH).setPrefixes("books:"); + + IndexOptions indexOptions = IndexOptions.defaultOptions().setDefinition(indexDefinition); + + Schema schema = new Schema() + .addField(new Schema.Field("title", Schema.FieldType.TEXT)) + .addField(new Schema.Field("price", Schema.FieldType.NUMERIC)); + + String createResult = exec(commandObjects.ftCreate(indexName, indexOptions, schema)); + assertThat(createResult, equalTo("OK")); + + // Add a book to the index + String bookId = "books:123"; + + Map bookFields = new HashMap<>(); + bookFields.put("title", "Redis for Dummies"); + bookFields.put("price", 29.99); + + Long hsetResult = exec(commandObjects.hsetObject(bookId, bookFields)); + assertThat(hsetResult, equalTo(2L)); + + Query query = new Query("Redis").returnFields("title", "price"); + + String explanation = exec(commandObjects.ftExplain(indexName, query)); + assertThat(explanation, not(emptyOrNullString())); + + List explanationCli = exec(commandObjects.ftExplainCLI(indexName, query)); + assertThat(explanationCli, not(empty())); + } + + @Test + public void testFtAggregate() { + String indexName = "booksIndex"; + + IndexDefinition indexDefinition = new IndexDefinition(IndexDefinition.Type.HASH).setPrefixes("books:"); + + IndexOptions indexOptions = IndexOptions.defaultOptions().setDefinition(indexDefinition); + + Schema schema = new Schema() + .addField(new Schema.Field("title", Schema.FieldType.TEXT)) + .addField(new Schema.Field("price", Schema.FieldType.NUMERIC)) + .addField(new Schema.Field("genre", Schema.FieldType.TAG)); + + String createResult = exec(commandObjects.ftCreate(indexName, indexOptions, schema)); + assertThat(createResult, equalTo("OK")); + + // Add books to the index + Map book1Fields = new HashMap<>(); + book1Fields.put("title", "Redis for Dummies"); + book1Fields.put("price", 20.99); + book1Fields.put("genre", "Technology"); + + String book1Id = "books:101"; + + exec(commandObjects.hsetObject(book1Id, book1Fields)); + + Map book2Fields = new HashMap<>(); + book2Fields.put("title", "Advanced Redis"); + book2Fields.put("price", 25.99); + book2Fields.put("genre", "Technology"); + + String book2Id = "books:102"; + + exec(commandObjects.hsetObject(book2Id, book2Fields)); + + // Aggregation: average price of books in the 'Technology' genre + AggregationBuilder aggr = new AggregationBuilder() + .groupBy("@genre", Reducers.avg("@price").as("avgPrice")) + .filter("@genre=='Technology'"); + + AggregationResult aggregationResult = exec(commandObjects.ftAggregate(indexName, aggr)); + + assertThat(aggregationResult, notNullValue()); + assertThat(aggregationResult.getResults(), hasSize(1)); + + Map result = aggregationResult.getResults().get(0); + assertThat(result, hasEntry("genre", "Technology")); + assertThat(result, hasEntry("avgPrice", "23.49")); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsServerManagementCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsServerManagementCommandsTest.java new file mode 100644 index 0000000000..543f2dc6d9 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsServerManagementCommandsTest.java @@ -0,0 +1,92 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; + +import org.junit.Test; +import redis.clients.jedis.CommandObject; +import redis.clients.jedis.RedisProtocol; + +/** + * Tests related to Server management commands. + */ +public class CommandObjectsServerManagementCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsServerManagementCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testSlowLogReset() { + String reset = exec(commandObjects.slowlogReset()); + assertThat(reset, equalTo("OK")); + } + + @Test + public void testMemoryUsage() { + String key = "key"; + int samples = 5; + + exec(commandObjects.set(key, "value")); + + CommandObject memoryUsage = commandObjects.memoryUsage(key); + assertThat(exec(memoryUsage), greaterThan(0L)); + + CommandObject memoryUsageWithSamples = commandObjects.memoryUsage(key, samples); + assertThat(exec(memoryUsageWithSamples), greaterThan(0L)); + + CommandObject memoryUsageBinary = commandObjects.memoryUsage(key.getBytes()); + assertThat(exec(memoryUsageBinary), greaterThan(0L)); + + CommandObject memoryUsageBinaryWithSamples = commandObjects.memoryUsage(key.getBytes(), samples); + assertThat(exec(memoryUsageBinaryWithSamples), greaterThan(0L)); + } + + @Test + public void testObjectRefcount() { + String key = "refcountKey"; + + exec(commandObjects.set(key, "value")); + + Long refcount = exec(commandObjects.objectRefcount(key)); + + assertThat(refcount, greaterThanOrEqualTo(1L)); + + Long refcountBinary = exec(commandObjects.objectRefcount(key.getBytes())); + + assertThat(refcountBinary, greaterThanOrEqualTo(1L)); + } + + @Test + public void testObjectEncoding() { + exec(commandObjects.lpush("lst", "Hello, Redis!")); + + String encoding = exec(commandObjects.objectEncoding("lst")); + + assertThat(encoding, containsString("list")); + + byte[] encodingBinary = exec(commandObjects.objectEncoding("lst".getBytes())); + + assertThat(new String(encodingBinary), containsString("list")); + } + + @Test + public void testObjectIdletime() throws InterruptedException { + String key = "idleTestString"; + String value = "Idle value test"; + + exec(commandObjects.set(key, value)); + + // A small delay to simulate idle time + Thread.sleep(1000); + + Long idleTime = exec(commandObjects.objectIdletime(key)); + assertThat(idleTime, greaterThan(0L)); + + Long idleTimeBinary = exec(commandObjects.objectIdletime(key.getBytes())); + assertThat(idleTimeBinary, greaterThan(0L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java new file mode 100644 index 0000000000..6a6874ef4d --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java @@ -0,0 +1,373 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.not; + +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; + +/** + * Tests related to Set commands. + */ +public class CommandObjectsSetCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsSetCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testSetCommands() { + String key = "testSet"; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + Long sadd = exec(commandObjects.sadd(key, member1, member2, member3)); + assertThat(sadd, equalTo(3L)); + + Set members = exec(commandObjects.smembers(key)); + assertThat(members, containsInAnyOrder(member1, member2, member3)); + + Long srem = exec(commandObjects.srem(key, member1)); + assertThat(srem, equalTo(1L)); + + Set membersAfterSrem = exec(commandObjects.smembers(key)); + assertThat(membersAfterSrem, containsInAnyOrder(member2, member3)); + } + + @Test + public void testSetCommandsBinary() { + byte[] key = "testSetB".getBytes(); + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + byte[] member3 = "member3".getBytes(); + + Long sadd = exec(commandObjects.sadd(key, member1, member2, member3)); + assertThat(sadd, equalTo(3L)); + + Set members = exec(commandObjects.smembers(key)); + assertThat(members, containsInAnyOrder(member1, member2, member3)); + + Long srem = exec(commandObjects.srem(key, member1)); + assertThat(srem, equalTo(1L)); + + Set membersAfterSrem = exec(commandObjects.smembers(key)); + assertThat(membersAfterSrem, containsInAnyOrder(member2, member3)); + } + + @Test + public void testSpop() { + String key = "testSetPop"; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + Long sadd = exec(commandObjects.sadd(key, member1, member2, member3)); + assertThat(sadd, equalTo(3L)); + + String spop = exec(commandObjects.spop(key)); + assertThat(spop, anyOf(equalTo(member1), equalTo(member2), equalTo(member3))); + + Set spopMultiple = exec(commandObjects.spop(key, 2)); + assertThat(spopMultiple, hasSize(2)); + assertThat(spopMultiple, everyItem(anyOf(equalTo(member1), equalTo(member2), equalTo(member3)))); + assertThat(spopMultiple, not(contains(spop))); + } + + @Test + public void testSpopBinary() { + byte[] bkey = "testSetPopB".getBytes(); + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + byte[] member3 = "member3".getBytes(); + + Long sadd = exec(commandObjects.sadd(bkey, member1, member2, member3)); + assertThat(sadd, equalTo(3L)); + + byte[] spop = exec(commandObjects.spop(bkey)); + assertThat(spop, anyOf(equalTo(member1), equalTo(member2), equalTo(member3))); + + Set spopMultiple = exec(commandObjects.spop(bkey, 2)); + assertThat(spopMultiple, hasSize(2)); + assertThat(spopMultiple, everyItem(anyOf(equalTo(member1), equalTo(member2), equalTo(member3)))); + assertThat(spopMultiple, not(contains(spop))); + } + + @Test + public void testSetMembershipCommands() { + String key = "testSetMembership"; + String member1 = "member1"; + String member2 = "member2"; + + exec(commandObjects.sadd(key, member1, member2)); + + Long scard = exec(commandObjects.scard(key)); + assertThat(scard, equalTo(2L)); + + Long scardBinary = exec(commandObjects.scard(key.getBytes())); + assertThat(scardBinary, equalTo(2L)); + + Boolean isMember = exec(commandObjects.sismember(key, member1)); + assertThat(isMember, equalTo(true)); + + Boolean isMemberBinary = exec(commandObjects.sismember(key.getBytes(), member1.getBytes())); + assertThat(isMemberBinary, equalTo(true)); + + List mIsMember = exec(commandObjects.smismember(key, member1, "nonMember")); + assertThat(mIsMember, contains(true, false)); + + List mIsMemberBinary = exec(commandObjects.smismember(key.getBytes(), member1.getBytes(), "nonMember".getBytes())); + assertThat(mIsMemberBinary, contains(true, false)); + } + + @Test + public void testSrandmemberCommands() { + String key = "testSetRandomMember"; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + exec(commandObjects.sadd(key, member1, member2, member3)); + + String randomMember = exec(commandObjects.srandmember(key)); + assertThat(randomMember, anyOf(equalTo(member1), equalTo(member2), equalTo(member3))); + + byte[] randomMemberBinary = exec(commandObjects.srandmember(key.getBytes())); + assertThat(new String(randomMemberBinary), anyOf(equalTo(member1), equalTo(member2), equalTo(member3))); + + List randomMembers = exec(commandObjects.srandmember(key, 2)); + assertThat(randomMembers, hasSize(2)); + assertThat(randomMembers, everyItem(anyOf(equalTo(member1), equalTo(member2), equalTo(member3)))); + assertThat(randomMembers, not(contains(randomMember))); + + List randomMembersBinary = exec(commandObjects.srandmember(key.getBytes(), 2)); + assertThat(randomMembersBinary, hasSize(2)); + assertThat(randomMembersBinary, everyItem(anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()), equalTo(member3.getBytes())))); + assertThat(randomMembersBinary, not(contains(randomMemberBinary))); + } + + @Test + public void testSscanCommands() { + String key = "testSetScan"; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + exec(commandObjects.sadd(key, member1, member2, member3)); + + ScanParams params = new ScanParams().count(2); + + ScanResult scan = exec(commandObjects.sscan(key, ScanParams.SCAN_POINTER_START, params)); + + assertThat(scan.getResult(), hasSize(lessThanOrEqualTo(3))); + assertThat(scan.getResult(), everyItem(anyOf(equalTo(member1), equalTo(member2), equalTo(member3)))); + + ScanResult scanBinary = exec(commandObjects.sscan(key.getBytes(), ScanParams.SCAN_POINTER_START_BINARY, params)); + + assertThat(scanBinary.getResult(), hasSize(lessThanOrEqualTo(3))); + assertThat(scanBinary.getResult(), everyItem(anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()), equalTo(member3.getBytes())))); + } + + @Test + public void testSdiff() { + String key1 = "testSet1"; + String key2 = "testSet2"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member2", "member3", "member4")); + + Set diff = exec(commandObjects.sdiff(key1, key2)); + assertThat(diff, contains("member1")); + + Set diffBinary = exec(commandObjects.sdiff(key1.getBytes(), key2.getBytes())); + assertThat(diffBinary, contains("member1".getBytes())); + } + + @Test + public void testSdiffstore() { + String key1 = "testSet1"; + String key2 = "testSet2"; + String dstKey = "testSetDiff"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member2", "member3", "member4")); + + Long diffStore = exec(commandObjects.sdiffstore(dstKey, key1, key2)); + assertThat(diffStore, equalTo(1L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, contains("member1")); + } + + @Test + public void testSdiffstoreBinary() { + byte[] key1 = "testSet1".getBytes(); + byte[] key2 = "testSet2".getBytes(); + byte[] dstKey = "testSetDiff".getBytes(); + + exec(commandObjects.sadd(key1, "member1".getBytes(), "member2".getBytes(), "member3".getBytes())); + exec(commandObjects.sadd(key2, "member2".getBytes(), "member3".getBytes(), "member4".getBytes())); + + Long diffStore = exec(commandObjects.sdiffstore(dstKey, key1, key2)); + assertThat(diffStore, equalTo(1L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, contains("member1".getBytes())); + } + + @Test + public void testSinterAndSinterCard() { + String key1 = "testSetInter1"; + String key2 = "testSetInter2"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member2", "member3", "member4")); + + Set inter = exec(commandObjects.sinter(key1, key2)); + assertThat(inter, containsInAnyOrder("member2", "member3")); + + Set interBinary = exec(commandObjects.sinter(key1.getBytes(), key2.getBytes())); + assertThat(interBinary, containsInAnyOrder("member2".getBytes(), "member3".getBytes())); + + Long interCard = exec(commandObjects.sintercard(key1, key2)); + assertThat(interCard, equalTo(2L)); + + Long interCardBinary = exec(commandObjects.sintercard(key1.getBytes(), key2.getBytes())); + assertThat(interCardBinary, equalTo(2L)); + + Long interCardLimited = exec(commandObjects.sintercard(1, key1, key2)); + assertThat(interCardLimited, equalTo(1L)); + + Long interCardLimitedBinary = exec(commandObjects.sintercard(1, key1.getBytes(), key2.getBytes())); + assertThat(interCardLimitedBinary, equalTo(1L)); + } + + @Test + public void testSinterstore() { + String key1 = "testSetInter1"; + String key2 = "testSetInter2"; + String dstKey = "testSetInterResult"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member2", "member3", "member4")); + + Long interStore = exec(commandObjects.sinterstore(dstKey, key1, key2)); + assertThat(interStore, equalTo(2L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, containsInAnyOrder("member2", "member3")); + } + + @Test + public void testSinterstoreBinary() { + byte[] key1 = "testSetInter1B".getBytes(); + byte[] key2 = "testSetInter2B".getBytes(); + byte[] dstKey = "testSetInterResultB".getBytes(); + + exec(commandObjects.sadd(key1, "member1".getBytes(), "member2".getBytes(), "member3".getBytes())); + exec(commandObjects.sadd(key2, "member2".getBytes(), "member3".getBytes(), "member4".getBytes())); + + Long interStore = exec(commandObjects.sinterstore(dstKey, key1, key2)); + assertThat(interStore, equalTo(2L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, containsInAnyOrder("member2".getBytes(), "member3".getBytes())); + } + + @Test + public void testSunion() { + String key1 = "testSetUnion1"; + String key2 = "testSetUnion2"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member3", "member4", "member5")); + + Set unionResult = exec(commandObjects.sunion(key1, key2)); + + assertThat(unionResult, containsInAnyOrder( + "member1", "member2", "member3", "member4", "member5")); + + Set bunionResult = exec(commandObjects.sunion(key1.getBytes(), key2.getBytes())); + + assertThat(bunionResult, containsInAnyOrder( + "member1".getBytes(), "member2".getBytes(), "member3".getBytes(), "member4".getBytes(), "member5".getBytes())); + } + + @Test + public void testSunionstore() { + String key1 = "testSetUnion1"; + String key2 = "testSetUnion2"; + String dstKey = "testSetUnionResult"; + + exec(commandObjects.sadd(key1, "member1", "member2", "member3")); + exec(commandObjects.sadd(key2, "member3", "member4", "member5")); + + Long unionStore = exec(commandObjects.sunionstore(dstKey, key1, key2)); + + assertThat(unionStore, equalTo(5L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + + assertThat(dstSet, containsInAnyOrder( + "member1", "member2", "member3", "member4", "member5")); + } + + @Test + public void testSunionstoreBinary() { + byte[] key1 = "testSetUnion1".getBytes(); + byte[] key2 = "testSetUnion2".getBytes(); + byte[] dstKey = "testSetUnionResult".getBytes(); + + exec(commandObjects.sadd(key1, "member1".getBytes(), "member2".getBytes(), "member3".getBytes())); + exec(commandObjects.sadd(key2, "member3".getBytes(), "member4".getBytes(), "member5".getBytes())); + + Long unionStore = exec(commandObjects.sunionstore(dstKey, key1, key2)); + assertThat(unionStore, equalTo(5L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, containsInAnyOrder( + "member1".getBytes(), "member2".getBytes(), "member3".getBytes(), "member4".getBytes(), "member5".getBytes())); + } + + @Test + public void testSmove() { + String srcKey = "testSetSrc"; + String dstKey = "testSetDst"; + String member = "memberToMove"; + + exec(commandObjects.sadd(srcKey, member)); + + Long smove = exec(commandObjects.smove(srcKey, dstKey, member)); + assertThat(smove, equalTo(1L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, contains(member)); + } + + @Test + public void testSmoveBinary() { + byte[] srcKey = "testSetSrc".getBytes(); + byte[] dstKey = "testSetDst".getBytes(); + byte[] member = "memberToMove".getBytes(); + + exec(commandObjects.sadd(srcKey, member)); + + Long smove = exec(commandObjects.smove(srcKey, dstKey, member)); + assertThat(smove, equalTo(1L)); + + Set dstSet = exec(commandObjects.smembers(dstKey)); + assertThat(dstSet, contains(member)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java new file mode 100644 index 0000000000..cf2be1b0a7 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java @@ -0,0 +1,1508 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.either; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.SortedSetOption; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.ZAddParams; +import redis.clients.jedis.params.ZIncrByParams; +import redis.clients.jedis.params.ZParams; +import redis.clients.jedis.params.ZRangeParams; +import redis.clients.jedis.resps.ScanResult; +import redis.clients.jedis.resps.Tuple; +import redis.clients.jedis.util.KeyValue; + +/** + * Tests related to Sorted set commands. + */ +public class CommandObjectsSortedSetCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsSortedSetCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testZaddAndZcard() { + String key = "zset"; + String member = "member1"; + double score = 1.0; + + Map scoreMembers = new HashMap<>(); + scoreMembers.put("member2", 2.0); + scoreMembers.put("member3", 3.0); + + ZAddParams params = ZAddParams.zAddParams().nx(); + + Long zadd = exec(commandObjects.zadd(key, score, member)); + assertThat(zadd, equalTo(1L)); + + Long zaddParams = exec(commandObjects.zadd(key, score, member, params)); + assertThat(zaddParams, equalTo(0L)); + + Long zaddMultiple = exec(commandObjects.zadd(key, scoreMembers)); + assertThat(zaddMultiple, equalTo(2L)); + + Long zaddMultipleParams = exec(commandObjects.zadd(key, scoreMembers, params)); + assertThat(zaddMultipleParams, equalTo(0L)); + + Long zcard = exec(commandObjects.zcard(key)); + assertThat(zcard, equalTo(3L)); + } + + @Test + public void testZaddAndZcardBinary() { + byte[] key = "zset".getBytes(); + byte[] member = "member1".getBytes(); + double score = 1.0; + + Map binaryScoreMembers = new HashMap<>(); + binaryScoreMembers.put("member2".getBytes(), 2.0); + binaryScoreMembers.put("member3".getBytes(), 3.0); + + ZAddParams params = ZAddParams.zAddParams().nx(); + + Long zadd = exec(commandObjects.zadd(key, score, member)); + assertThat(zadd, equalTo(1L)); + + Long zaddParams = exec(commandObjects.zadd(key, score, member, params)); + assertThat(zaddParams, equalTo(0L)); + + Long zaddMultiple = exec(commandObjects.zadd(key, binaryScoreMembers)); + assertThat(zaddMultiple, equalTo(2L)); + + Long zaddMultipleParams = exec(commandObjects.zadd(key, binaryScoreMembers, params)); + assertThat(zaddMultipleParams, equalTo(0L)); + + Long zcard = exec(commandObjects.zcard(key)); + assertThat(zcard, equalTo(3L)); + } + + @Test + public void testZIncrAndZincrBy() { + String key = "zset"; + String member = "member"; + double initialScore = 1.0; + double increment = 2.0; + + ZAddParams zAddParams = ZAddParams.zAddParams().xx(); + + ZIncrByParams zIncrByParams = ZIncrByParams.zIncrByParams().xx(); + + Long zadd = exec(commandObjects.zadd(key, initialScore, member)); + assertThat(zadd, equalTo(1L)); + + Double zaddIncr = exec(commandObjects.zaddIncr(key, increment, member, zAddParams)); + assertThat(zaddIncr, closeTo(initialScore + increment, 0.001)); + + Double zscoreAfterZaddincr = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZaddincr, closeTo(initialScore + increment, 0.001)); + + Double zincrBy = exec(commandObjects.zincrby(key, increment, member)); + assertThat(zincrBy, closeTo(initialScore + increment * 2, 0.001)); + + Double zscoreAfterZincrBy = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZincrBy, closeTo(initialScore + increment * 2, 0.001)); + + Double zincrByParams = exec(commandObjects.zincrby(key, increment, member, zIncrByParams)); + assertThat(zincrByParams, closeTo(initialScore + increment * 3, 0.001)); + + Double zscoreAfterZincrByParams = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZincrByParams, closeTo(initialScore + increment * 3, 0.001)); + } + + @Test + public void testZIncrAndZincrByBinary() { + byte[] key = "zset".getBytes(); + byte[] member = "member".getBytes(); + double initialScore = 1.0; + double increment = 2.0; + + ZAddParams zAddParams = ZAddParams.zAddParams().xx(); + + ZIncrByParams zIncrByParams = ZIncrByParams.zIncrByParams().xx(); + + Long zadd = exec(commandObjects.zadd(key, initialScore, member)); + assertThat(zadd, equalTo(1L)); + + Double zaddIncr = exec(commandObjects.zaddIncr(key, increment, member, zAddParams)); + assertThat(zaddIncr, closeTo(initialScore + increment, 0.001)); + + Double zscoreAfterZaddIncr = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZaddIncr, closeTo(initialScore + increment, 0.001)); + + Double zincrBy = exec(commandObjects.zincrby(key, increment, member)); + assertThat(zincrBy, closeTo(initialScore + increment * 2, 0.001)); + + Double zscoreAfterZincrBy = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZincrBy, closeTo(initialScore + increment * 2, 0.001)); + + Double zincrByParams = exec(commandObjects.zincrby(key, increment, member, zIncrByParams)); + assertThat(zincrByParams, closeTo(initialScore + increment * 3, 0.001)); + + Double zscoreAfterZincrByParams = exec(commandObjects.zscore(key, member)); + assertThat(zscoreAfterZincrByParams, closeTo(initialScore + increment * 3, 0.001)); + } + + @Test + public void testZrem() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List zrangeBefore = exec(commandObjects.zrange(key, 0, -1)); + assertThat(zrangeBefore, containsInAnyOrder(member1, member2)); + + Long removedCount = exec(commandObjects.zrem(key, member1)); + assertThat(removedCount, equalTo(1L)); + + List zrangeAfter = exec(commandObjects.zrange(key, 0, -1)); + assertThat(zrangeAfter, containsInAnyOrder(member2)); + } + + @Test + public void testZremBinary() { + byte[] key = "zset".getBytes(); + byte[] member1 = "one".getBytes(); + byte[] member2 = "two".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List zrangeBefore = exec(commandObjects.zrange(key, 0, -1)); + assertThat(zrangeBefore, containsInAnyOrder(member1, member2)); + + Long removedCount = exec(commandObjects.zrem(key, member1)); + assertThat(removedCount, equalTo(1L)); + + List zrangeAfter = exec(commandObjects.zrange(key, 0, -1)); + assertThat(zrangeAfter, containsInAnyOrder(member2)); + } + + @Test + public void testZrandmember() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + String randomMember = exec(commandObjects.zrandmember(key)); + + assertThat(randomMember, anyOf(equalTo(member1), equalTo(member2))); + + byte[] randomMemberBinary = exec(commandObjects.zrandmember(key.getBytes())); + + assertThat(randomMemberBinary, anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()))); + + List randomMembers = exec(commandObjects.zrandmember(key, 2)); + + assertThat(randomMembers, containsInAnyOrder(member1, member2)); + + List randomMembersBinary = exec(commandObjects.zrandmember(key.getBytes(), 2)); + + assertThat(randomMembersBinary.get(0), anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()))); + assertThat(randomMembersBinary.get(1), anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()))); + } + + @Test + public void testZrandmemberWithScores() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List randomMembersWithScores = exec(commandObjects.zrandmemberWithScores(key, 2)); + + assertThat(randomMembersWithScores, hasSize(2)); + assertThat(randomMembersWithScores, containsInAnyOrder(new Tuple(member1, score1), new Tuple(member2, score2))); + + List randomMembersWithScoresBinary = exec(commandObjects.zrandmemberWithScores(key.getBytes(), 2)); + + assertThat(randomMembersWithScoresBinary, hasSize(2)); + + assertThat(randomMembersWithScoresBinary.get(0).getBinaryElement(), anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()))); + assertThat(randomMembersWithScoresBinary.get(0).getScore(), anyOf(equalTo(score1), equalTo(score2))); + + assertThat(randomMembersWithScoresBinary.get(1).getBinaryElement(), anyOf(equalTo(member1.getBytes()), equalTo(member2.getBytes()))); + assertThat(randomMembersWithScoresBinary.get(1).getScore(), anyOf(equalTo(score1), equalTo(score2))); + } + + @Test + public void testZscore() { + String key = "zset"; + String member1 = "one"; + double score1 = 1.0; + + exec(commandObjects.zadd(key, score1, member1)); + + Double score = exec(commandObjects.zscore(key, member1)); + assertThat(score, equalTo(score1)); + + Double scoreBinary = exec(commandObjects.zscore(key.getBytes(), member1.getBytes())); + assertThat(scoreBinary, equalTo(score1)); + } + + @Test + public void testZmscore() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List scores = exec(commandObjects.zmscore(key, member1, member2)); + assertThat(scores, contains(score1, score2)); + + List scoresBinary = exec(commandObjects.zmscore(key.getBytes(), member1.getBytes(), member2.getBytes())); + assertThat(scoresBinary, contains(score1, score2)); + } + + @Test + public void testZrankAndZrevrank() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + Long rankMember1 = exec(commandObjects.zrank(key, member1)); + assertThat(rankMember1, equalTo(0L)); + + Long rankMember2 = exec(commandObjects.zrank(key, member2)); + assertThat(rankMember2, equalTo(1L)); + + Long rankMember1Binary = exec(commandObjects.zrank(key.getBytes(), member1.getBytes())); + assertThat(rankMember1Binary, equalTo(0L)); + + Long rankMember2Binary = exec(commandObjects.zrank(key.getBytes(), member2.getBytes())); + assertThat(rankMember2Binary, equalTo(1L)); + + Long revRankMember1 = exec(commandObjects.zrevrank(key, member1)); + assertThat(revRankMember1, equalTo(1L)); + + Long revRankMember2 = exec(commandObjects.zrevrank(key, member2)); + assertThat(revRankMember2, equalTo(0L)); + + Long revRankMember1Binary = exec(commandObjects.zrevrank(key.getBytes(), member1.getBytes())); + assertThat(revRankMember1Binary, equalTo(1L)); + + Long revRankMember2Binary = exec(commandObjects.zrevrank(key.getBytes(), member2.getBytes())); + assertThat(revRankMember2Binary, equalTo(0L)); + } + + @Test + public void testZrankWithScoreAndZrevrankWithScore() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + KeyValue rankWithScoreMember1 = exec(commandObjects.zrankWithScore(key, member1)); + assertThat(rankWithScoreMember1.getKey(), equalTo(0L)); + assertThat(rankWithScoreMember1.getValue(), equalTo(score1)); + + KeyValue rankWithScoreMember2 = exec(commandObjects.zrankWithScore(key, member2)); + assertThat(rankWithScoreMember2.getKey(), equalTo(1L)); + assertThat(rankWithScoreMember2.getValue(), equalTo(score2)); + + KeyValue rankWithScoreMember1Binary = exec(commandObjects.zrankWithScore(key.getBytes(), member1.getBytes())); + assertThat(rankWithScoreMember1Binary.getKey(), equalTo(0L)); + assertThat(rankWithScoreMember1Binary.getValue(), equalTo(score1)); + + KeyValue rankWithScoreMember2Binary = exec(commandObjects.zrankWithScore(key.getBytes(), member2.getBytes())); + assertThat(rankWithScoreMember2Binary.getKey(), equalTo(1L)); + assertThat(rankWithScoreMember2Binary.getValue(), equalTo(score2)); + + KeyValue revRankWithScoreMember1 = exec(commandObjects.zrevrankWithScore(key, member1)); + assertThat(revRankWithScoreMember1.getKey(), equalTo(1L)); + assertThat(revRankWithScoreMember1.getValue(), equalTo(score1)); + + KeyValue revRankWithScoreMember2 = exec(commandObjects.zrevrankWithScore(key, member2)); + assertThat(revRankWithScoreMember2.getKey(), equalTo(0L)); + assertThat(revRankWithScoreMember2.getValue(), equalTo(score2)); + + KeyValue revRankWithScoreMember1Binary = exec(commandObjects.zrevrankWithScore(key.getBytes(), member1.getBytes())); + assertThat(revRankWithScoreMember1Binary.getKey(), equalTo(1L)); + assertThat(revRankWithScoreMember1Binary.getValue(), equalTo(score1)); + + KeyValue revRankWithScoreMember2Binary = exec(commandObjects.zrevrankWithScore(key.getBytes(), member2.getBytes())); + assertThat(revRankWithScoreMember2Binary.getKey(), equalTo(0L)); + assertThat(revRankWithScoreMember2Binary.getValue(), equalTo(score2)); + } + + @Test + public void testZpopmax() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + Tuple poppedMax = exec(commandObjects.zpopmax(key)); + assertThat(poppedMax.getElement(), equalTo(member2)); + assertThat(poppedMax.getScore(), equalTo(score2)); + + List poppedMaxMultiple = exec(commandObjects.zpopmax(key, 2)); + assertThat(poppedMaxMultiple, hasSize(1)); // Since we already popped the max, only one remains + assertThat(poppedMaxMultiple.get(0).getElement(), equalTo(member1)); + assertThat(poppedMaxMultiple.get(0).getScore(), equalTo(score1)); + } + + @Test + public void testZpopmaxBinary() { + byte[] key = "zset".getBytes(); + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1.getBytes())); + exec(commandObjects.zadd(key, score2, member2.getBytes())); + + Tuple poppedMaxBinary = exec(commandObjects.zpopmax(key)); + assertThat(poppedMaxBinary.getBinaryElement(), equalTo(member2.getBytes())); + assertThat(poppedMaxBinary.getScore(), equalTo(score2)); + + List poppedMaxMultipleBinary = exec(commandObjects.zpopmax(key, 2)); + assertThat(poppedMaxMultipleBinary, hasSize(1)); // Since we already popped the max, only one remains + assertThat(poppedMaxMultipleBinary.get(0).getBinaryElement(), equalTo(member1.getBytes())); + assertThat(poppedMaxMultipleBinary.get(0).getScore(), equalTo(score1)); + } + + @Test + public void testZpopmin() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + Tuple poppedMin = exec(commandObjects.zpopmin(key)); + assertThat(poppedMin.getElement(), equalTo(member1)); + assertThat(poppedMin.getScore(), equalTo(score1)); + + List poppedMinMultiple = exec(commandObjects.zpopmin(key, 2)); + assertThat(poppedMinMultiple, hasSize(1)); // Since we already popped the min, only one remains + assertThat(poppedMinMultiple.get(0).getElement(), equalTo(member2)); + assertThat(poppedMinMultiple.get(0).getScore(), equalTo(score2)); + } + + @Test + public void testZpopminBinary() { + byte[] key = "zset".getBytes(); + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1.getBytes())); + exec(commandObjects.zadd(key, score2, member2.getBytes())); + + Tuple poppedMinBinary = exec(commandObjects.zpopmin(key)); + assertThat(poppedMinBinary.getBinaryElement(), equalTo(member1.getBytes())); + assertThat(poppedMinBinary.getScore(), equalTo(score1)); + + List poppedMinMultipleBinary = exec(commandObjects.zpopmin(key, 2)); + assertThat(poppedMinMultipleBinary, hasSize(1)); // Since we already popped the min, only one remains + assertThat(poppedMinMultipleBinary.get(0).getBinaryElement(), equalTo(member2.getBytes())); + assertThat(poppedMinMultipleBinary.get(0).getScore(), equalTo(score2)); + } + + @Test + public void testBzpopmaxAndBzpopmin() { + String key1 = "zset1"; + String key2 = "zset2"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + double timeout = 2.0; // 2 seconds timeout for blocking operations + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue poppedMax = exec(commandObjects.bzpopmax(timeout, key1, key2)); + assertThat(poppedMax.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(poppedMax.getValue().getScore(), anyOf(equalTo(score1), equalTo(score2))); + + KeyValue poppedMin = exec(commandObjects.bzpopmin(timeout, key1, key2)); + assertThat(poppedMin.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(poppedMin.getValue().getScore(), anyOf(equalTo(score1), equalTo(score2))); + } + + @Test + public void testBzpopmaxAndBzpopminBinary() { + byte[] key1 = "zset1".getBytes(); + byte[] key2 = "zset2".getBytes(); + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + double timeout = 2.0; // 2 seconds timeout for blocking operations + + exec(commandObjects.zadd(key1, score1, member1.getBytes())); + exec(commandObjects.zadd(key2, score2, member2.getBytes())); + + KeyValue poppedMaxBinary = exec(commandObjects.bzpopmax(timeout, key1, key2)); + assertThat(poppedMaxBinary.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(poppedMaxBinary.getValue().getScore(), anyOf(equalTo(score1), equalTo(score2))); + + KeyValue poppedMinBinary = exec(commandObjects.bzpopmin(timeout, key1, key2)); + assertThat(poppedMinBinary.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(poppedMinBinary.getValue().getScore(), anyOf(equalTo(score1), equalTo(score2))); + } + + @Test + public void testZcount() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + String member3 = "three"; + double score1 = 1.0; + double score2 = 2.0; + double score3 = 3.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + exec(commandObjects.zadd(key, score3, member3)); + + Long countInNumericRange = exec(commandObjects.zcount(key, 1.5, 2.5)); + assertThat(countInNumericRange, equalTo(1L)); + + Long countInStringRange = exec(commandObjects.zcount(key, "(1", "3")); + assertThat(countInStringRange, equalTo(2L)); + + Long countInNumericRangeBinary = exec(commandObjects.zcount(key.getBytes(), 1.5, 2.5)); + assertThat(countInNumericRangeBinary, equalTo(1L)); + + Long countInBinaryRange = exec(commandObjects.zcount(key.getBytes(), "(1".getBytes(), "3".getBytes())); + assertThat(countInBinaryRange, equalTo(2L)); + } + + @Test + public void testZrange() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List range = exec(commandObjects.zrange(key, 0, -1)); + assertThat(range, contains(member1, member2)); + + List rangeBinary = exec(commandObjects.zrange(key.getBytes(), 0, -1)); + assertThat(rangeBinary, contains(member1.getBytes(), member2.getBytes())); + + ZRangeParams zRangeParams = ZRangeParams.zrangeParams(0, -1); + + List rangeWithParams = exec(commandObjects.zrange(key, zRangeParams)); + assertThat(rangeWithParams, hasItems(member1, member2)); + + List rangeWithParamsBinary = exec(commandObjects.zrange(key.getBytes(), zRangeParams)); + assertThat(rangeWithParamsBinary.get(0), equalTo(member1.getBytes())); + assertThat(rangeWithParamsBinary.get(1), equalTo(member2.getBytes())); + } + + @Test + public void testZrangeWithScores() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List rangeWithScores = exec(commandObjects.zrangeWithScores(key, 0, -1)); + + assertThat(rangeWithScores, hasSize(2)); + assertThat(rangeWithScores.get(0).getElement(), equalTo(member1)); + assertThat(rangeWithScores.get(0).getScore(), equalTo(score1)); + assertThat(rangeWithScores.get(1).getElement(), equalTo(member2)); + assertThat(rangeWithScores.get(1).getScore(), equalTo(score2)); + + List rangeWithScoresBinary = exec(commandObjects.zrangeWithScores(key.getBytes(), 0, -1)); + + assertThat(rangeWithScoresBinary, hasSize(2)); + assertThat(rangeWithScoresBinary.get(0).getBinaryElement(), equalTo(member1.getBytes())); + assertThat(rangeWithScoresBinary.get(0).getScore(), equalTo(score1)); + assertThat(rangeWithScoresBinary.get(1).getBinaryElement(), equalTo(member2.getBytes())); + assertThat(rangeWithScoresBinary.get(1).getScore(), equalTo(score2)); + + ZRangeParams zRangeParams = ZRangeParams.zrangeParams(0, -1); + + List rangeWithScoresParams = exec(commandObjects.zrangeWithScores(key, zRangeParams)); + + assertThat(rangeWithScoresParams, hasSize(2)); + assertThat(rangeWithScoresParams.get(0).getElement(), equalTo(member1)); + assertThat(rangeWithScoresParams.get(0).getScore(), equalTo(score1)); + assertThat(rangeWithScoresParams.get(1).getElement(), equalTo(member2)); + assertThat(rangeWithScoresParams.get(1).getScore(), equalTo(score2)); + + List rangeWithScoresParamsBinary = exec(commandObjects.zrangeWithScores(key.getBytes(), zRangeParams)); + + assertThat(rangeWithScoresParamsBinary, hasSize(2)); + assertThat(rangeWithScoresParamsBinary.get(0).getBinaryElement(), equalTo(member1.getBytes())); + assertThat(rangeWithScoresParamsBinary.get(0).getScore(), equalTo(score1)); + assertThat(rangeWithScoresParamsBinary.get(1).getBinaryElement(), equalTo(member2.getBytes())); + assertThat(rangeWithScoresParamsBinary.get(1).getScore(), equalTo(score2)); + } + + @Test + public void testZrangestore() { + String srcKey = "zsetSrc"; + String destKey = "zsetDest"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(srcKey, score1, member1)); + exec(commandObjects.zadd(srcKey, score2, member2)); + + ZRangeParams zRangeParams = ZRangeParams.zrangeByScoreParams(score1, score2); + + Long zrangeStore = exec(commandObjects.zrangestore(destKey, srcKey, zRangeParams)); + + assertThat(zrangeStore, equalTo(2L)); + + List zrangeWithScores = exec(commandObjects.zrangeWithScores(destKey, 0, -1)); + + assertThat(zrangeWithScores, hasSize(2)); + assertThat(zrangeWithScores.get(0).getElement(), equalTo(member1)); + assertThat(zrangeWithScores.get(1).getElement(), equalTo(member2)); + } + + @Test + public void testZrangestoreBinary() { + byte[] srcKey = "zsetSrcB".getBytes(); + byte[] destKey = "zsetDestB".getBytes(); + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(srcKey, score1, member1.getBytes())); + exec(commandObjects.zadd(srcKey, score2, member2.getBytes())); + + ZRangeParams zRangeParams = ZRangeParams.zrangeByScoreParams(score1, score2); + + Long zrangeStore = exec(commandObjects.zrangestore(destKey, srcKey, zRangeParams)); + + assertThat(zrangeStore, equalTo(2L)); + + List zrangeWithScores = exec(commandObjects.zrangeWithScores(destKey, 0, -1)); + + assertThat(zrangeWithScores, hasSize(2)); + assertThat(zrangeWithScores.get(0).getBinaryElement(), equalTo(member1.getBytes())); + assertThat(zrangeWithScores.get(1).getBinaryElement(), equalTo(member2.getBytes())); + } + + @Test + public void testZrevrange() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List revRange = exec(commandObjects.zrevrange(key, 0, -1)); + assertThat(revRange, contains(member2, member1)); + + List revRangeBinary = exec(commandObjects.zrevrange(key.getBytes(), 0, -1)); + assertThat(revRangeBinary, contains(member2.getBytes(), member1.getBytes())); + } + + @Test + public void testZrevrangeWithScores() { + String key = "zset"; + String member1 = "one"; + String member2 = "two"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + List revRangeWithScores = exec(commandObjects.zrevrangeWithScores(key, 0, -1)); + + assertThat(revRangeWithScores, hasSize(2)); + assertThat(revRangeWithScores.get(0).getElement(), equalTo(member2)); + assertThat(revRangeWithScores.get(0).getScore(), equalTo(score2)); + assertThat(revRangeWithScores.get(1).getElement(), equalTo(member1)); + assertThat(revRangeWithScores.get(1).getScore(), equalTo(score1)); + + List revRangeWithScoresBinary = exec(commandObjects.zrevrangeWithScores(key.getBytes(), 0, -1)); + + assertThat(revRangeWithScoresBinary, hasSize(2)); + assertThat(revRangeWithScoresBinary.get(0).getBinaryElement(), equalTo(member2.getBytes())); + assertThat(revRangeWithScoresBinary.get(0).getScore(), equalTo(score2)); + assertThat(revRangeWithScoresBinary.get(1).getBinaryElement(), equalTo(member1.getBytes())); + assertThat(revRangeWithScoresBinary.get(1).getScore(), equalTo(score1)); + } + + @Test + public void testZrangeByScore() { + String key = "zset"; + double min = 1.0; + double max = 10.0; + String smin = "1"; + String smax = "10"; + byte[] bmin = "1.0".getBytes(); + byte[] bmax = "10.0".getBytes(); + int offset = 0; + int count = 1; + + exec(commandObjects.zadd(key, 1, "one")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 3, "three")); + exec(commandObjects.zadd(key, 13, "four")); + + List numericRange = exec(commandObjects.zrangeByScore(key, min, max)); + assertThat(numericRange, contains("one", "two", "three")); + + List stringRange = exec(commandObjects.zrangeByScore(key, smin, smax)); + assertThat(stringRange, contains("one", "two", "three")); + + List numericRangeOffsetCount = exec(commandObjects.zrangeByScore(key, min, max, offset, count)); + assertThat(numericRangeOffsetCount, contains("one")); + + List stringRangeOffsetCount = exec(commandObjects.zrangeByScore(key, smin, smax, offset, count)); + assertThat(stringRangeOffsetCount, contains("one")); + + List numericRangeBinary = exec(commandObjects.zrangeByScore(key.getBytes(), min, max)); + assertThat(numericRangeBinary.get(0), equalTo("one".getBytes())); + assertThat(numericRangeBinary.get(1), equalTo("two".getBytes())); + assertThat(numericRangeBinary.get(2), equalTo("three".getBytes())); + + List stringRangeBinary = exec(commandObjects.zrangeByScore(key.getBytes(), bmin, bmax)); + assertThat(stringRangeBinary, contains("one".getBytes(), "two".getBytes(), "three".getBytes())); + + List numericRangeOffsetCountBinary = exec(commandObjects.zrangeByScore(key.getBytes(), min, max, offset, count)); + assertThat(numericRangeOffsetCountBinary.get(0), equalTo("one".getBytes())); + + List stringRangeOffsetCountBinary = exec(commandObjects.zrangeByScore(key.getBytes(), bmin, bmax, offset, count)); + assertThat(stringRangeOffsetCountBinary, contains("one".getBytes())); + } + + @Test + public void testZrevrangeByScore() { + String key = "zset"; + double max = 10.0; + double min = 1.0; + String smax = "10"; + String smin = "1"; + byte[] bmax = "10.0".getBytes(); + byte[] bmin = "1.0".getBytes(); + int offset = 0; + int count = 1; + + exec(commandObjects.zadd(key, 13, "four")); + exec(commandObjects.zadd(key, 3, "three")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 1, "one")); + + List numericRevrange = exec(commandObjects.zrevrangeByScore(key, max, min)); + assertThat(numericRevrange, contains("three", "two", "one")); + + List stringRevrange = exec(commandObjects.zrevrangeByScore(key, smax, smin)); + assertThat(stringRevrange, contains("three", "two", "one")); + + List numericRevrangeOffsetCount = exec(commandObjects.zrevrangeByScore(key, max, min, offset, count)); + assertThat(numericRevrangeOffsetCount, contains("three")); + + List stringRevrangeOffsetCount = exec(commandObjects.zrevrangeByScore(key, smax, smin, offset, count)); + assertThat(stringRevrangeOffsetCount, contains("three")); + + List numericRevrangeBinary = exec(commandObjects.zrevrangeByScore(key.getBytes(), max, min)); + assertThat(numericRevrangeBinary, contains("three".getBytes(), "two".getBytes(), "one".getBytes())); + + List stringRevrangeBinary = exec(commandObjects.zrevrangeByScore(key.getBytes(), bmax, bmin)); + assertThat(stringRevrangeBinary, contains("three".getBytes(), "two".getBytes(), "one".getBytes())); + + List numericRevrangeOffsetCountBinary = exec(commandObjects.zrevrangeByScore(key.getBytes(), max, min, offset, count)); + assertThat(numericRevrangeOffsetCountBinary.get(0), equalTo("three".getBytes())); + + List stringRevrangeOffsetCountBinary = exec(commandObjects.zrevrangeByScore(key.getBytes(), bmax, bmin, offset, count)); + assertThat(stringRevrangeOffsetCountBinary, contains("three".getBytes())); + } + + @Test + public void testZrangeByScoreWithScores() { + String key = "zset"; + double min = 1.0; + double max = 10.0; + String smin = "1"; + String smax = "10"; + byte[] bmin = "1.0".getBytes(); + byte[] bmax = "10.0".getBytes(); + int offset = 0; + int count = 2; + + exec(commandObjects.zadd(key, 1, "one")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 3, "three")); + + List numericRange = exec(commandObjects.zrangeByScoreWithScores(key, min, max)); + assertThat(numericRange, contains( + new Tuple("one", 1d), + new Tuple("two", 2d), + new Tuple("three", 3d))); + + List stringRange = exec(commandObjects.zrangeByScoreWithScores(key, smin, smax)); + assertThat(stringRange, contains( + new Tuple("one", 1d), + new Tuple("two", 2d), + new Tuple("three", 3d))); + + List numericRangeOffsetCount = exec(commandObjects.zrangeByScoreWithScores(key, min, max, offset, count)); + assertThat(numericRangeOffsetCount, contains( + new Tuple("one", 1d), + new Tuple("two", 2d))); + + List stringRangeOffsetCount = exec(commandObjects.zrangeByScoreWithScores(key, smin, smax, offset, count)); + assertThat(stringRangeOffsetCount, contains( + new Tuple("one", 1d), + new Tuple("two", 2d))); + + List numericRangeBinary = exec(commandObjects.zrangeByScoreWithScores(key.getBytes(), min, max)); + assertThat(numericRangeBinary, contains( + new Tuple("one".getBytes(), 1d), + new Tuple("two".getBytes(), 2d), + new Tuple("three".getBytes(), 3d))); + + List stringRangeBinary = exec(commandObjects.zrangeByScoreWithScores(key.getBytes(), bmin, bmax)); + assertThat(stringRangeBinary, contains( + new Tuple("one".getBytes(), 1d), + new Tuple("two".getBytes(), 2d), + new Tuple("three".getBytes(), 3d))); + + List numericRangeOffsetCountBinary = exec(commandObjects.zrangeByScoreWithScores(key.getBytes(), min, max, offset, count)); + assertThat(numericRangeOffsetCountBinary, contains( + new Tuple("one".getBytes(), 1d), + new Tuple("two".getBytes(), 2d))); + + List stringRangeOffsetCountBinary = exec(commandObjects.zrangeByScoreWithScores(key.getBytes(), bmin, bmax, offset, count)); + assertThat(stringRangeOffsetCountBinary, contains( + new Tuple("one".getBytes(), 1d), + new Tuple("two".getBytes(), 2d))); + } + + @Test + public void testZrevrangeByScoreWithScores() { + String key = "zset"; + double max = 10.0; + double min = 1.0; + String smax = "10"; + String smin = "1"; + byte[] bmax = "10".getBytes(); + byte[] bmin = "1".getBytes(); + int offset = 0; + int count = 2; + + exec(commandObjects.zadd(key, 3, "three")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 1, "one")); + + List numericRevrange = exec(commandObjects.zrevrangeByScoreWithScores(key, max, min)); + assertThat(numericRevrange, contains( + new Tuple("three", 3d), + new Tuple("two", 2d), + new Tuple("one", 1d))); + + List stringRevrange = exec(commandObjects.zrevrangeByScoreWithScores(key, smax, smin)); + assertThat(stringRevrange, contains( + new Tuple("three", 3d), + new Tuple("two", 2d), + new Tuple("one", 1d))); + + List numericRevrangeOffsetCount = exec(commandObjects.zrevrangeByScoreWithScores(key, max, min, offset, count)); + assertThat(numericRevrangeOffsetCount, contains( + new Tuple("three", 3d), + new Tuple("two", 2d))); + + List stringRevrangeOffsetCount = exec(commandObjects.zrevrangeByScoreWithScores(key, smax, smin, offset, count)); + assertThat(stringRevrangeOffsetCount, contains( + new Tuple("three", 3d), + new Tuple("two", 2d))); + + List numericRevrangeBinary = exec(commandObjects.zrevrangeByScoreWithScores(key.getBytes(), max, min)); + assertThat(numericRevrangeBinary, contains( + new Tuple("three".getBytes(), 3d), + new Tuple("two".getBytes(), 2d), + new Tuple("one".getBytes(), 1d))); + + List stringRevrangeBinary = exec(commandObjects.zrevrangeByScoreWithScores(key.getBytes(), bmax, bmin)); + assertThat(stringRevrangeBinary, contains( + new Tuple("three".getBytes(), 3d), + new Tuple("two".getBytes(), 2d), + new Tuple("one".getBytes(), 1d))); + + List numericRevrangeOffsetCountBinary = exec(commandObjects.zrevrangeByScoreWithScores(key.getBytes(), max, min, offset, count)); + assertThat(numericRevrangeOffsetCountBinary, contains( + new Tuple("three".getBytes(), 3d), + new Tuple("two".getBytes(), 2d))); + + List stringRevrangeOffsetCountBinary = exec(commandObjects.zrevrangeByScoreWithScores(key.getBytes(), bmax, bmin, offset, count)); + assertThat(stringRevrangeOffsetCountBinary, contains( + new Tuple("three".getBytes(), 3d), + new Tuple("two".getBytes(), 2d))); + } + + @Test + public void testZremrangeByRank() { + String key = "zset"; + long start = 0; + long stop = 1; + + exec(commandObjects.zadd(key, 1, "one")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 3, "three")); + + Long removedCount = exec(commandObjects.zremrangeByRank(key, start, stop)); + assertThat(removedCount, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("three")); + } + + @Test + public void testZremrangeByRankBinary() { + byte[] key = "zset".getBytes(); + long start = 0; + long stop = 1; + + exec(commandObjects.zadd(key, 1, "one".getBytes())); + exec(commandObjects.zadd(key, 2, "two".getBytes())); + exec(commandObjects.zadd(key, 3, "three".getBytes())); + + Long removedCount = exec(commandObjects.zremrangeByRank(key, start, stop)); + assertThat(removedCount, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("three".getBytes())); + } + + @Test + public void testZremrangeByScore() { + String key = "zset"; + double min = 1.0; + double max = 2.0; + String smin = "1"; + String smax = "2"; + + exec(commandObjects.zadd(key, 1, "one")); + exec(commandObjects.zadd(key, 2, "two")); + exec(commandObjects.zadd(key, 3, "three")); + + Long removedCountNumeric = exec(commandObjects.zremrangeByScore(key, min, max)); + assertThat(removedCountNumeric, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("three")); + + exec(commandObjects.zadd(key, 1, "one")); + exec(commandObjects.zadd(key, 2, "two")); + + Long removedCountString = exec(commandObjects.zremrangeByScore(key, smin, smax)); + assertThat(removedCountString, equalTo(2L)); + + remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("three")); + } + + @Test + public void testZremrangeByScoreBinary() { + byte[] bkey = "zset".getBytes(); + double min = 1.0; + double max = 2.0; + byte[] bmin = "1".getBytes(); + byte[] bmax = "2".getBytes(); + + exec(commandObjects.zadd(bkey, 1, "one".getBytes())); + exec(commandObjects.zadd(bkey, 2, "two".getBytes())); + exec(commandObjects.zadd(bkey, 3, "three".getBytes())); + + Long removedCountNumericBinary = exec(commandObjects.zremrangeByScore(bkey, min, max)); + assertThat(removedCountNumericBinary, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(bkey, 0, -1)); + assertThat(remainingElements, contains("three".getBytes())); + + exec(commandObjects.zadd(bkey, 1, "one".getBytes())); + exec(commandObjects.zadd(bkey, 2, "two".getBytes())); + + Long removedCountStringBinary = exec(commandObjects.zremrangeByScore(bkey, bmin, bmax)); + assertThat(removedCountStringBinary, equalTo(2L)); + + remainingElements = exec(commandObjects.zrange(bkey, 0, -1)); + assertThat(remainingElements, contains("three".getBytes())); + } + + @Test + public void testZlexcount() { + String key = "zset"; + String min = "[a", max = "(g"; + + exec(commandObjects.zadd(key, 0, "abc")); + exec(commandObjects.zadd(key, 0, "def")); + exec(commandObjects.zadd(key, 0, "ghi")); + + Long count = exec(commandObjects.zlexcount(key, min, max)); + assertThat(count, equalTo(2L)); + + Long countBinary = exec(commandObjects.zlexcount(key.getBytes(), min.getBytes(), max.getBytes())); + assertThat(countBinary, equalTo(2L)); + } + + @Test + public void testZrangeByLex() { + String key = "zset"; + String min = "[abc"; + String max = "(cde"; + int offset = 0; + int count = 2; + + exec(commandObjects.zadd(key, 0, "aaa")); + exec(commandObjects.zadd(key, 0, "abc")); + exec(commandObjects.zadd(key, 0, "bcd")); + exec(commandObjects.zadd(key, 0, "cde")); + + List range = exec(commandObjects.zrangeByLex(key, min, max)); + assertThat(range, contains("abc", "bcd")); + + List limitedRange = exec(commandObjects.zrangeByLex(key, min, max, offset, count)); + assertThat(limitedRange, contains("abc", "bcd")); + + List rangeBinary = exec(commandObjects.zrangeByLex(key.getBytes(), min.getBytes(), max.getBytes())); + assertThat(rangeBinary, contains("abc".getBytes(), "bcd".getBytes())); + + List limitedRangeBinary = exec(commandObjects.zrangeByLex(key.getBytes(), min.getBytes(), max.getBytes(), offset, count)); + assertThat(limitedRangeBinary, contains("abc".getBytes(), "bcd".getBytes())); + } + + @Test + public void testZrevrangeByLex() { + String key = "zset"; + String max = "[cde"; + String min = "(aaa"; + int offset = 0; + int count = 2; + + exec(commandObjects.zadd(key, 0, "aaa")); + exec(commandObjects.zadd(key, 0, "abc")); + exec(commandObjects.zadd(key, 0, "bcd")); + exec(commandObjects.zadd(key, 0, "cde")); + + List revRange = exec(commandObjects.zrevrangeByLex(key, max, min)); + assertThat(revRange, contains("cde", "bcd", "abc")); + + List limitedRevRange = exec(commandObjects.zrevrangeByLex(key, max, min, offset, count)); + assertThat(limitedRevRange, contains("cde", "bcd")); + + List revRangeBinary = exec(commandObjects.zrevrangeByLex(key.getBytes(), max.getBytes(), min.getBytes())); + assertThat(revRangeBinary.get(0), equalTo("cde".getBytes())); + assertThat(revRangeBinary.get(1), equalTo("bcd".getBytes())); + assertThat(revRangeBinary.get(2), equalTo("abc".getBytes())); + + List limitedRevRangeBinary = exec(commandObjects.zrevrangeByLex(key.getBytes(), max.getBytes(), min.getBytes(), offset, count)); + assertThat(limitedRevRangeBinary.get(0), equalTo("cde".getBytes())); + assertThat(limitedRevRangeBinary.get(1), equalTo("bcd".getBytes())); + } + + @Test + public void testZremrangeByLex() { + String key = "zset"; + String min = "[aaa"; + String max = "(ccc"; + + exec(commandObjects.zadd(key, 0, "aaa")); + exec(commandObjects.zadd(key, 0, "bbb")); + exec(commandObjects.zadd(key, 0, "ccc")); + + Long removedCount = exec(commandObjects.zremrangeByLex(key, min, max)); + assertThat(removedCount, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("ccc")); + } + + @Test + public void testZremrangeByLexBinary() { + byte[] key = "zset".getBytes(); + byte[] min = "[aaa".getBytes(); + byte[] bmax = "(ccc".getBytes(); + + exec(commandObjects.zadd(key, 0, "aaa".getBytes())); + exec(commandObjects.zadd(key, 0, "bbb".getBytes())); + exec(commandObjects.zadd(key, 0, "ccc".getBytes())); + + Long removedCount = exec(commandObjects.zremrangeByLex(key, min, bmax)); + assertThat(removedCount, equalTo(2L)); + + List remainingElements = exec(commandObjects.zrange(key, 0, -1)); + assertThat(remainingElements, contains("ccc".getBytes())); + } + + @Test + public void testZscan() { + String key = "zset"; + String cursor = "0"; + ScanParams params = new ScanParams().count(2); + String member1 = "one"; + double score1 = 1.0; + String member2 = "two"; + double score2 = 2.0; + + exec(commandObjects.zadd(key, score1, member1)); + exec(commandObjects.zadd(key, score2, member2)); + + ScanResult result = exec(commandObjects.zscan(key, cursor, params)); + assertThat(result.getResult(), containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2))); + + ScanResult resultBinar = exec(commandObjects.zscan(key.getBytes(), cursor.getBytes(), params)); + assertThat(resultBinar.getResult(), containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2))); + } + + @Test + public void testZdiffAndZdiffWithScores() { + String key1 = "zset1"; + String key2 = "zset2"; + String member1 = "one"; + double score1 = 1.0; + String member2 = "two"; + double score2 = 2.0; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key1, score2, member2)); + exec(commandObjects.zadd(key2, score1, member1)); + + List diff = exec(commandObjects.zdiff(key1, key2)); + assertThat(diff, containsInAnyOrder(member2)); + + List diffWithScores = exec(commandObjects.zdiffWithScores(key1, key2)); + assertThat(diffWithScores, containsInAnyOrder(new Tuple(member2, score2))); + + List diffBinary = exec(commandObjects.zdiff(key1.getBytes(), key2.getBytes())); + assertThat(diffBinary, containsInAnyOrder(member2.getBytes())); + + List diffWithScoresBinary = exec(commandObjects.zdiffWithScores(key1.getBytes(), key2.getBytes())); + assertThat(diffWithScoresBinary, containsInAnyOrder(new Tuple(member2.getBytes(), score2))); + } + + @Test + public void testZdiffStore() { + String dstKey = "result"; + + exec(commandObjects.zadd("set1", 1, "member1")); + exec(commandObjects.zadd("set1", 2, "member2")); + exec(commandObjects.zadd("set2", 3, "member2")); + + Long result = exec(commandObjects.zdiffStore(dstKey, "set1", "set2")); + assertThat(result, equalTo(1L)); + + List resultSet = exec(commandObjects.zrange(dstKey, 0, -1)); + assertThat(resultSet, containsInAnyOrder("member1")); + + exec(commandObjects.del(dstKey)); + + result = exec(commandObjects.zdiffstore(dstKey, "set1", "set2")); + assertThat(result, equalTo(1L)); + + resultSet = exec(commandObjects.zrange(dstKey, 0, -1)); + assertThat(resultSet, hasSize(1)); + assertThat(resultSet, containsInAnyOrder("member1")); + } + + @Test + public void testZdiffStoreBinary() { + byte[] dstKey = "result".getBytes(); + + exec(commandObjects.zadd("set1".getBytes(), 1, "member1".getBytes())); + exec(commandObjects.zadd("set1".getBytes(), 2, "member2".getBytes())); + exec(commandObjects.zadd("set2".getBytes(), 3, "member2".getBytes())); + + Long result = exec(commandObjects.zdiffStore(dstKey, "set1".getBytes(), "set2".getBytes())); + assertThat(result, equalTo(1L)); + + List resultSet = exec(commandObjects.zrange(dstKey, 0, -1)); + assertThat(resultSet, hasSize(1)); + assertThat(resultSet, containsInAnyOrder("member1".getBytes())); + + exec(commandObjects.del(dstKey)); + + result = exec(commandObjects.zdiffstore(dstKey, "set1".getBytes(), "set2".getBytes())); + assertThat(result, equalTo(1L)); + + resultSet = exec(commandObjects.zrange(dstKey, 0, -1)); + assertThat(resultSet, hasSize(1)); + assertThat(resultSet, containsInAnyOrder("member1".getBytes())); + } + + @Test + public void testZinterAndZintercard() { + ZParams params = new ZParams().aggregate(ZParams.Aggregate.SUM).weights(1, 2); + + exec(commandObjects.zadd("set1", 1, "member1")); + exec(commandObjects.zadd("set2", 2, "member1")); + exec(commandObjects.zadd("set2", 2, "member2")); + + List inter = exec(commandObjects.zinter(params, "set1", "set2")); + assertThat(inter, containsInAnyOrder("member1")); + + List interWithScores = exec(commandObjects.zinterWithScores(params, "set1", "set2")); + assertThat(interWithScores, containsInAnyOrder( + new Tuple("member1", 5.0))); + + Long card = exec(commandObjects.zintercard("set1", "set2")); + assertThat(card, equalTo(1L)); + + Long cardLimited = exec(commandObjects.zintercard(1L, "set1", "set2")); + assertThat(cardLimited, equalTo(1L)); + + List interBinary = exec(commandObjects.zinter(params, "set1".getBytes(), "set2".getBytes())); + assertThat(interBinary, containsInAnyOrder("member1".getBytes())); + + List interWithScoresBinary = exec(commandObjects.zinterWithScores(params, "set1".getBytes(), "set2".getBytes())); + assertThat(interWithScoresBinary, hasItem( + new Tuple("member1".getBytes(), 5.0))); + + Long cardBinary = exec(commandObjects.zintercard("set1".getBytes(), "set2".getBytes())); + assertThat(cardBinary, equalTo(1L)); + + Long cardLimitedBinary = exec(commandObjects.zintercard(1L, "set1".getBytes(), "set2".getBytes())); + assertThat(cardLimitedBinary, equalTo(1L)); + } + + @Test + public void testZinterstore() { + String dstKey = "destinationIntersect"; + String set1 = "sortedSet1"; + String set2 = "sortedSet2"; + String set3 = "sortedSet3"; + double score1 = 1.0; + double score2 = 2.0; + double score3 = 3.0; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + exec(commandObjects.zadd(set1, score1, member1)); + exec(commandObjects.zadd(set1, score2, member2)); + + exec(commandObjects.zadd(set2, score2, member2)); + exec(commandObjects.zadd(set2, score3, member3)); + + exec(commandObjects.zadd(set3, score1, member1)); + exec(commandObjects.zadd(set3, score3, member3)); + + ZParams params = new ZParams().aggregate(ZParams.Aggregate.SUM); + + Long interStore = exec(commandObjects.zinterstore(dstKey, set1, set2, set3)); + assertThat(interStore, equalTo(0L)); + + Long interStoreWithParams = exec(commandObjects.zinterstore(dstKey, params, set1, set2)); + assertThat(interStoreWithParams, equalTo(1L)); + + List dstSetContent = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContent, hasSize(1)); + assertThat(dstSetContent.get(0).getElement(), equalTo(member2)); + assertThat(dstSetContent.get(0).getScore(), equalTo(score2 * 2)); // Score aggregated as SUM + } + + @Test + public void testZinterstoreBinary() { + byte[] dstKey = "destinationIntersect".getBytes(); + byte[] set1 = "sortedSet1".getBytes(); + byte[] set2 = "sortedSet2".getBytes(); + byte[] set3 = "sortedSet3".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + double score3 = 3.0; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + byte[] member3 = "member3".getBytes(); + + exec(commandObjects.zadd(set1, score1, member1)); + exec(commandObjects.zadd(set1, score2, member2)); + + exec(commandObjects.zadd(set2, score2, member2)); + exec(commandObjects.zadd(set2, score3, member3)); + + exec(commandObjects.zadd(set3, score1, member1)); + exec(commandObjects.zadd(set3, score3, member3)); + + ZParams params = new ZParams().aggregate(ZParams.Aggregate.SUM); + + Long interStore = exec(commandObjects.zinterstore(dstKey, set1, set2, set3)); + assertThat(interStore, equalTo(0L)); + + List dstSetContent = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContent, empty()); + + Long interStoreParams = exec(commandObjects.zinterstore(dstKey, params, set1, set2)); + assertThat(interStoreParams, equalTo(1L)); + + List dstSetParamsContent = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetParamsContent, hasSize(1)); + assertThat(dstSetParamsContent.get(0).getBinaryElement(), equalTo(member2)); + assertThat(dstSetParamsContent.get(0).getScore(), equalTo(score2 * 2)); // Score aggregated as SUM + } + + @Test + public void testZunionAndZunionWithScores() { + String key1 = "sortedSet1"; + String key2 = "sortedSet2"; + String member1 = "member1"; + String member2 = "member2"; + double score1 = 1.0; + double score2 = 2.0; + + exec(commandObjects.zadd(key1, score1, member1)); + + exec(commandObjects.zadd(key2, score2, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + ZParams params = new ZParams().aggregate(ZParams.Aggregate.SUM); + + List zunion = exec(commandObjects.zunion(params, key1, key2)); + assertThat(zunion, containsInAnyOrder(member1, member2)); + + List zunionWithScores = exec(commandObjects.zunionWithScores(params, key1, key2)); + assertThat(zunionWithScores, containsInAnyOrder( + new Tuple(member1, score1 + score2), + new Tuple(member2, score2))); + + List zunionBinary = exec(commandObjects.zunion(params, key1.getBytes(), key2.getBytes())); + assertThat(zunionBinary, containsInAnyOrder(member1.getBytes(), member2.getBytes())); + + List zunionWithScoresBinary = exec(commandObjects.zunionWithScores(params, key1.getBytes(), key2.getBytes())); + assertThat(zunionWithScoresBinary, containsInAnyOrder( + new Tuple(member1, score1 + score2), + new Tuple(member2, score2))); + } + + @Test + public void testZunionstore() { + String dstKey = "destinationSet"; + String set1 = "sortedSet1"; + String set2 = "sortedSet2"; + double score1 = 1.0; + double score2 = 2.0; + double score3 = 3.0; + String member1 = "member1"; + String member2 = "member2"; + String member3 = "member3"; + + exec(commandObjects.zadd(set1, score1, member1)); + exec(commandObjects.zadd(set1, score2, member2)); + exec(commandObjects.zadd(set1, score3, member3)); + + exec(commandObjects.zadd(set2, score3, member3)); + + ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX); + + Long zunionStore = exec(commandObjects.zunionstore(dstKey, set1, set2)); + assertThat(zunionStore, equalTo(3L)); + + List dstSetContent = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContent, containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2), + new Tuple(member3, score3 * 2))); + + Long zunionStoreParams = exec(commandObjects.zunionstore(dstKey, params, set1, set2)); + assertThat(zunionStoreParams, equalTo(3L)); + + List dstSetContentParams = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContentParams, containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2), + new Tuple(member3, score3))); + } + + @Test + public void testZunionstoreBinary() { + byte[] dstKey = "destinationSet".getBytes(); + byte[] set1 = "sortedSet1".getBytes(); + byte[] set2 = "sortedSet2".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + double score3 = 3.0; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + byte[] member3 = "member3".getBytes(); + + exec(commandObjects.zadd(set1, score1, member1)); + exec(commandObjects.zadd(set1, score2, member2)); + exec(commandObjects.zadd(set1, score3, member3)); + + exec(commandObjects.zadd(set2, score3, member3)); + + ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX); + + Long zunionStore = exec(commandObjects.zunionstore(dstKey, set1, set2)); + assertThat(zunionStore, equalTo(3L)); + + List dstSetContent = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContent, containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2), + new Tuple(member3, score3 * 2))); + + Long zunionStoreParams = exec(commandObjects.zunionstore(dstKey, params, set1, set2)); + assertThat(zunionStoreParams, equalTo(3L)); + + List dstSetContentParams = exec(commandObjects.zrangeWithScores(dstKey, 0, -1)); + assertThat(dstSetContentParams, containsInAnyOrder( + new Tuple(member1, score1), + new Tuple(member2, score2), + new Tuple(member3, score3))); + } + + @Test + public void testZmpopAndZmpopWithCount() { + String key1 = "sortedSet1"; + String key2 = "sortedSet2"; + double score1 = 1.0; + double score2 = 2.0; + String member1 = "member1"; + String member2 = "member2"; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> zmpop = exec(commandObjects.zmpop(SortedSetOption.MAX, key1, key2)); + + assertThat(zmpop, notNullValue()); + assertThat(zmpop.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(zmpop.getValue(), hasSize(1)); + + KeyValue> zmpopCount = exec(commandObjects.zmpop(SortedSetOption.MIN, 2, key1, key2)); + + assertThat(zmpopCount, notNullValue()); + assertThat(zmpopCount.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(zmpopCount.getValue(), hasSize(1)); + } + + @Test + public void testZmpopAndZmpopWithCountBinary() { + byte[] key1 = "sortedSet1".getBytes(); + byte[] key2 = "sortedSet2".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> zmpopBinary = exec(commandObjects.zmpop(SortedSetOption.MAX, key1, key2)); + + assertThat(zmpopBinary, notNullValue()); + assertThat(zmpopBinary.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(zmpopBinary.getValue(), hasSize(1)); + + KeyValue> zmpopCountBinary = exec(commandObjects.zmpop(SortedSetOption.MIN, 2, key1, key2)); + + assertThat(zmpopCountBinary, notNullValue()); + assertThat(zmpopCountBinary.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(zmpopCountBinary.getValue(), hasSize(1)); + } + + @Test + public void testBzmpop() { + String key1 = "sortedSet1"; + String key2 = "sortedSet2"; + double score1 = 1.0; + double score2 = 2.0; + double timeout = 0.1; + String member1 = "member1"; + String member2 = "member2"; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpop = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, 1, key1, key2)); + assertThat(bzmpop, notNullValue()); + assertThat(bzmpop.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(bzmpop.getValue(), hasSize(1)); + } + + @Test + public void testBzmpopBinary() { + byte[] key1 = "sortedSet1".getBytes(); + byte[] key2 = "sortedSet2".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + double timeout = 0.1; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpopBinary = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, 1, key1, key2)); + assertThat(bzmpopBinary, notNullValue()); + assertThat(bzmpopBinary.getKey(), either(equalTo(key1)).or(equalTo(key2))); + assertThat(bzmpopBinary.getValue(), hasSize(1)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java new file mode 100644 index 0000000000..fa4a43ea80 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java @@ -0,0 +1,15 @@ +package redis.clients.jedis.commands.commandobjects; + +import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.RedisProtocol; + +/** + * Base class for tests that use the standalone client. + */ +public abstract class CommandObjectsStandaloneTestBase extends CommandObjectsTestBase { + + public CommandObjectsStandaloneTestBase(RedisProtocol protocol) { + super(protocol, HostAndPorts.getRedisServers().get(0), "foobared"); + } + +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java new file mode 100644 index 0000000000..2978544093 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java @@ -0,0 +1,1023 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.StreamEntryID; +import redis.clients.jedis.params.XAddParams; +import redis.clients.jedis.params.XAutoClaimParams; +import redis.clients.jedis.params.XClaimParams; +import redis.clients.jedis.params.XPendingParams; +import redis.clients.jedis.params.XReadGroupParams; +import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.resps.StreamConsumerInfo; +import redis.clients.jedis.resps.StreamConsumersInfo; +import redis.clients.jedis.resps.StreamEntry; +import redis.clients.jedis.resps.StreamFullInfo; +import redis.clients.jedis.resps.StreamGroupInfo; +import redis.clients.jedis.resps.StreamInfo; +import redis.clients.jedis.resps.StreamPendingEntry; +import redis.clients.jedis.resps.StreamPendingSummary; + +/** + * Tests related to Stream commands. + */ +public class CommandObjectsStreamCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsStreamCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testXaddAndXlen() { + String streamKey = "testStream"; + StreamEntryID entryID = StreamEntryID.NEW_ENTRY; + + Map entryData = new HashMap<>(); + entryData.put("field1", "value1"); + entryData.put("field2", "value2"); + + StreamEntryID addedEntryId = exec(commandObjects.xadd(streamKey, entryID, entryData)); + assertThat(addedEntryId, notNullValue()); + + XAddParams params = new XAddParams().maxLen(1000); + StreamEntryID addedEntryIdWithParams = exec(commandObjects.xadd(streamKey, params, entryData)); + assertThat(addedEntryIdWithParams, notNullValue()); + + Long streamLength = exec(commandObjects.xlen(streamKey)); + assertThat(streamLength, equalTo(2L)); + } + + @Test + public void testXaddAndXlenBinary() { + byte[] streamKey = "streamKey".getBytes(); + + Map entryData = new HashMap<>(); + entryData.put("field1".getBytes(), "value1".getBytes()); + entryData.put("field2".getBytes(), "value2".getBytes()); + + XAddParams params = new XAddParams().maxLen(1000); + byte[] addedEntryId = exec(commandObjects.xadd(streamKey, params, entryData)); + assertThat(addedEntryId, notNullValue()); + + Long streamLengthBytes = exec(commandObjects.xlen(streamKey)); + assertThat(streamLengthBytes, equalTo(1L)); + } + + @Test + public void testXrangeWithIdParameters() { + String key = "testStream"; + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData2)); + + List xrangeAll = exec(commandObjects.xrange(key, null, (StreamEntryID) null)); + assertThat(xrangeAll.size(), equalTo(2)); + assertThat(xrangeAll.get(0).getFields(), equalTo(entryData1)); + assertThat(xrangeAll.get(1).getFields(), equalTo(entryData2)); + + List xrangeAllCount = exec(commandObjects.xrange(key, null, (StreamEntryID) null, 1)); + assertThat(xrangeAllCount.size(), equalTo(1)); + assertThat(xrangeAllCount.get(0).getFields(), equalTo(entryData1)); + + List xrangeStartEnd = exec(commandObjects.xrange(key, startID, endID)); + assertThat(xrangeStartEnd.size(), equalTo(2)); + assertThat(xrangeStartEnd.get(0).getFields(), equalTo(entryData1)); + assertThat(xrangeStartEnd.get(1).getFields(), equalTo(entryData2)); + + List xrangeStartEndCount = exec(commandObjects.xrange(key, startID, endID, 1)); + assertThat(xrangeStartEndCount.size(), equalTo(1)); + assertThat(xrangeStartEndCount.get(0).getFields(), equalTo(entryData1)); + + List xrangeUnknown = exec(commandObjects.xrange("nonExistingStream", null, (StreamEntryID) null)); + assertThat(xrangeUnknown, empty()); + } + + @Test + public void testXrangeWithStringParameters() { + String key = "testStreamWithString"; + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData2)); + + String start = startID.toString(); + String end = endID.toString(); + + List xrangeStartEnd = exec(commandObjects.xrange(key, start, end)); + assertThat(xrangeStartEnd.size(), equalTo(2)); + assertThat(xrangeStartEnd.get(0).getFields(), equalTo(entryData1)); + assertThat(xrangeStartEnd.get(1).getFields(), equalTo(entryData2)); + + List xrangeStartEndCount = exec(commandObjects.xrange(key, start, end, 1)); + assertThat(xrangeStartEndCount.size(), equalTo(1)); + assertThat(xrangeStartEndCount.get(0).getFields(), equalTo(entryData1)); + + List xrangeUnknown = exec(commandObjects.xrange("nonExistingStream", start, end)); + assertThat(xrangeUnknown, empty()); + } + + @Test + public void testXrangeWithBinaryParameters() { + String keyStr = "testStreamWithBytes"; + byte[] key = keyStr.getBytes(); + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, entryData2)); + + byte[] start = startID.toString().getBytes(); + byte[] end = endID.toString().getBytes(); + + List xrangeAll = exec(commandObjects.xrange(key, null, null)); + assertThat(xrangeAll, hasSize(2)); + assertThat(xrangeAll.get(0), instanceOf(List.class)); + assertThat(((List) xrangeAll.get(0)).get(0), equalTo(start)); + assertThat(((List) xrangeAll.get(1)).get(0), equalTo(end)); + + List xrangeStartEnd = exec(commandObjects.xrange(key, start, end)); + assertThat(xrangeStartEnd, hasSize(2)); + assertThat(xrangeStartEnd.get(0), instanceOf(List.class)); + assertThat(((List) xrangeStartEnd.get(0)).get(0), equalTo(start)); + assertThat(((List) xrangeStartEnd.get(1)).get(0), equalTo(end)); + + List xrangeAllCount = exec(commandObjects.xrange(key, null, null, 1)); + assertThat(xrangeAllCount, hasSize(1)); + assertThat(xrangeAllCount.get(0), instanceOf(List.class)); + assertThat(((List) xrangeAllCount.get(0)).get(0), equalTo(start)); + + List xrangeStartEndCount = exec(commandObjects.xrange(key, start, end, 1)); + assertThat(xrangeStartEndCount, hasSize(1)); + assertThat(xrangeStartEndCount.get(0), instanceOf(List.class)); + assertThat(((List) xrangeStartEndCount.get(0)).get(0), equalTo(start)); + + List xrangeUnknown = exec(commandObjects.xrange("nonExistingStream".getBytes(), start, end)); + assertThat(xrangeUnknown, empty()); + } + + @Test + public void testXrevrangeWithIdParameters() { + String key = "testStreamForXrevrange"; + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData2)); + + List xrevrangeAll = exec(commandObjects.xrevrange(key, null, (StreamEntryID) null)); + assertThat(xrevrangeAll.size(), equalTo(2)); + assertThat(xrevrangeAll.get(0).getFields(), equalTo(entryData2)); // The latest entry comes first + assertThat(xrevrangeAll.get(1).getFields(), equalTo(entryData1)); + + List xrevrangeAllCount = exec(commandObjects.xrevrange(key, null, (StreamEntryID) null, 1)); + assertThat(xrevrangeAllCount.size(), equalTo(1)); + assertThat(xrevrangeAllCount.get(0).getFields(), equalTo(entryData2)); // Only the latest entry is returned + + List xrevrangeEndStart = exec(commandObjects.xrevrange(key, endID, startID)); + assertThat(xrevrangeEndStart.size(), equalTo(2)); + assertThat(xrevrangeEndStart.get(0).getFields(), equalTo(entryData2)); + assertThat(xrevrangeEndStart.get(1).getFields(), equalTo(entryData1)); + + List xrevrangeStartEndCount = exec(commandObjects.xrevrange(key, endID, startID, 1)); + assertThat(xrevrangeStartEndCount.size(), equalTo(1)); + assertThat(xrevrangeStartEndCount.get(0).getFields(), equalTo(entryData2)); + + List xrevrangeUnknown = exec(commandObjects.xrevrange("nonExistingStream", null, (StreamEntryID) null)); + assertThat(xrevrangeUnknown, empty()); + } + + @Test + public void testXrevrangeWithStringParameters() { + String key = "testStreamForXrevrangeString"; + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData2)); + + String start = startID.toString(); + String end = endID.toString(); + + List xrevrangeAll = exec(commandObjects.xrevrange(key, null, (StreamEntryID) null)); + assertThat(xrevrangeAll.size(), equalTo(2)); + assertThat(xrevrangeAll.get(0).getFields(), equalTo(entryData2)); // The latest entry comes first + assertThat(xrevrangeAll.get(1).getFields(), equalTo(entryData1)); + + List xrevrangeEndStart = exec(commandObjects.xrevrange(key, end, start)); + assertThat(xrevrangeEndStart.size(), equalTo(2)); + assertThat(xrevrangeEndStart.get(0).getFields(), equalTo(entryData2)); + assertThat(xrevrangeEndStart.get(1).getFields(), equalTo(entryData1)); + + List xrevrangeAllCount = exec(commandObjects.xrevrange(key, null, (StreamEntryID) null, 1)); + assertThat(xrevrangeAllCount.size(), equalTo(1)); + assertThat(xrevrangeAllCount.get(0).getFields(), equalTo(entryData2)); + + List xrevrangeEndStartCount = exec(commandObjects.xrevrange(key, end, start, 1)); + assertThat(xrevrangeEndStartCount.size(), equalTo(1)); + assertThat(xrevrangeEndStartCount.get(0).getFields(), equalTo(entryData2)); + + List xrevrangeUnknown = exec(commandObjects.xrevrange("nonExistingStream", end, start)); + assertThat(xrevrangeUnknown, empty()); + } + + @Test + public void testXrevrangeWithBinaryParameters() { + String keyStr = "testStreamForXrevrangeBytes"; + byte[] key = keyStr.getBytes(); + + Map entryData1 = new HashMap<>(); + entryData1.put("field1", "value1"); + + Map entryData2 = new HashMap<>(); + entryData2.put("field2", "value2"); + + StreamEntryID startID = exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, entryData1)); + StreamEntryID endID = exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, entryData2)); + + byte[] start = startID.toString().getBytes(); + byte[] end = endID.toString().getBytes(); + + List xrevrangeAll = exec(commandObjects.xrevrange(key, null, null)); + assertThat(xrevrangeAll, hasSize(2)); + assertThat(xrevrangeAll.get(0), instanceOf(List.class)); + assertThat(((List) xrevrangeAll.get(0)).get(0), equalTo(end)); + assertThat(((List) xrevrangeAll.get(1)).get(0), equalTo(start)); + + List xrevrangeEndStart = exec(commandObjects.xrevrange(key, end, start)); + assertThat(xrevrangeEndStart, hasSize(2)); + assertThat(xrevrangeEndStart.get(0), instanceOf(List.class)); + assertThat(((List) xrevrangeEndStart.get(0)).get(0), equalTo(end)); + assertThat(((List) xrevrangeEndStart.get(1)).get(0), equalTo(start)); + + List xrevrangeAllCount = exec(commandObjects.xrevrange(key, null, null, 1)); + assertThat(xrevrangeAllCount, hasSize(1)); + assertThat(xrevrangeAllCount.get(0), instanceOf(List.class)); + assertThat(((List) xrevrangeAllCount.get(0)).get(0), equalTo(end)); + + List xrevrangeEndStartCount = exec(commandObjects.xrevrange(key, end, start, 1)); + assertThat(xrevrangeEndStartCount, hasSize(1)); + assertThat(xrevrangeEndStartCount.get(0), instanceOf(List.class)); + assertThat(((List) xrevrangeEndStartCount.get(0)).get(0), equalTo(end)); + + List xrevrangeUnknown = exec(commandObjects.xrevrange("nonExistingStream".getBytes(), end, start)); + assertThat(xrevrangeUnknown, empty()); + } + + @Test + public void testXackXpending() { + String key = "testStreamForXackEffect"; + String group = "testGroup"; + String consumer = "testConsumer"; + + Map entryData = new HashMap<>(); + entryData.put("field1", "value1"); + + exec(commandObjects.xgroupCreate(key, group, new StreamEntryID(), true)); + + StreamEntryID entryID = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, entryData)); + + Map streams = Collections.singletonMap(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + + XReadGroupParams params = new XReadGroupParams(); + + List>> messages = exec(commandObjects.xreadGroup(group, consumer, params, streams)); + + assertThat(messages, hasSize(1)); + assertThat(messages.get(0).getKey(), equalTo(key)); + assertThat(messages.get(0).getValue(), hasSize(1)); + assertThat(messages.get(0).getValue().get(0).getID(), equalTo(entryID)); + + StreamPendingSummary pendingSummary = exec(commandObjects.xpending(key, group)); + assertThat(pendingSummary.getTotal(), equalTo(1L)); + + XPendingParams xPendingParams = new XPendingParams() + .start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(1000); + List pendingSummaryWithParams = exec(commandObjects.xpending(key, group, xPendingParams)); + + assertThat(pendingSummaryWithParams, hasSize(1)); + assertThat(pendingSummaryWithParams.get(0).getConsumerName(), equalTo(consumer)); + assertThat(pendingSummaryWithParams.get(0).getID(), equalTo(entryID)); + + Long ack = exec(commandObjects.xack(key, group, entryID)); + assertThat(ack, equalTo(1L)); + + pendingSummary = exec(commandObjects.xpending(key, group)); + assertThat(pendingSummary.getTotal(), equalTo(0L)); + + pendingSummaryWithParams = exec(commandObjects.xpending(key, group, xPendingParams)); + assertThat(pendingSummaryWithParams, empty()); + } + + @Test + public void testXackXPendingBinary() { + String keyStr = "testStreamForXackEffect"; + byte[] key = keyStr.getBytes(); + byte[] group = "testGroup".getBytes(); + byte[] consumer = "testConsumer".getBytes(); + + Map entryData = new HashMap<>(); + entryData.put("field1", "value1"); + + exec(commandObjects.xgroupCreate(key, group, new StreamEntryID().toString().getBytes(), true)); + + StreamEntryID entryID = exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, entryData)); + + Map.Entry stream = new AbstractMap.SimpleEntry<>(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY.toString().getBytes()); + + XReadGroupParams params = new XReadGroupParams(); + + List messages = exec(commandObjects.xreadGroup(group, consumer, params, stream)); + assertThat(messages, hasSize(1)); + + Object pendingSummary = exec(commandObjects.xpending(key, group)); + + assertThat(pendingSummary, instanceOf(List.class)); + assertThat(((List) pendingSummary).get(0), equalTo(1L)); + + XPendingParams xPendingParams = new XPendingParams() + .start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(1000); + + List pendingList = exec(commandObjects.xpending(key, group, xPendingParams)); + assertThat(pendingList, hasSize(1)); + + Long ack = exec(commandObjects.xack(key, group, entryID.toString().getBytes())); + assertThat(ack, equalTo(1L)); + + pendingSummary = exec(commandObjects.xpending(key, group)); + assertThat(pendingSummary, instanceOf(List.class)); + assertThat(((List) pendingSummary).get(0), equalTo(0L)); + + pendingList = exec(commandObjects.xpending(key, group, xPendingParams)); + assertThat(pendingList, empty()); + } + + @Test + public void testXGroupSetID() { + String key = "testStream"; + String groupName = "testGroup"; + + StreamEntryID initialId = new StreamEntryID(); + StreamEntryID newId = new StreamEntryID("0-1"); + StreamEntryID newId2 = new StreamEntryID("0-2"); + + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value"))); + + exec(commandObjects.xgroupCreate(key, groupName, initialId, false)); + + List groupIdBefore = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdBefore, hasSize(1)); + assertThat(groupIdBefore.get(0).getName(), equalTo(groupName)); + assertThat(groupIdBefore.get(0).getLastDeliveredId(), equalTo(initialId)); + + String xgroupSetId = exec(commandObjects.xgroupSetID(key, groupName, newId)); + assertThat(xgroupSetId, equalTo("OK")); + + List groupIdAfter = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfter, hasSize(1)); + assertThat(groupIdAfter.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfter.get(0).getLastDeliveredId(), equalTo(newId)); + + String xgroupSetIdBinary = exec(commandObjects.xgroupSetID(key.getBytes(), groupName.getBytes(), newId2.toString().getBytes())); + assertThat(xgroupSetIdBinary, equalTo("OK")); + + List groupIdAfterBinary = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfterBinary, hasSize(1)); + assertThat(groupIdAfterBinary.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfterBinary.get(0).getLastDeliveredId(), equalTo(newId2)); + + List binaryGroupIdAfterBinary = exec(commandObjects.xinfoGroups(key.getBytes())); + assertThat(binaryGroupIdAfterBinary, notNullValue()); + } + + @Test + public void testXGroupDestroy() { + String key = "testStream"; + String groupName = "testGroup"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value"))); + + exec(commandObjects.xgroupCreate(key, groupName, initialId, false)); + + List groupIdBefore = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdBefore, hasSize(1)); + assertThat(groupIdBefore.get(0).getName(), equalTo(groupName)); + assertThat(groupIdBefore.get(0).getLastDeliveredId(), equalTo(initialId)); + + Long xgroupDestroy = exec(commandObjects.xgroupDestroy(key, groupName)); + assertThat(xgroupDestroy, equalTo(1L)); + + List groupInfoAfter = exec(commandObjects.xinfoGroups(key)); + assertThat(groupInfoAfter, empty()); + + // Re-create the group + exec(commandObjects.xgroupCreate(key, groupName, initialId, false)); + + List groupIdBeforeBinary = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdBeforeBinary, hasSize(1)); + assertThat(groupIdBeforeBinary.get(0).getName(), equalTo(groupName)); + assertThat(groupIdBeforeBinary.get(0).getLastDeliveredId(), equalTo(initialId)); + + Long xgroupDestroyBinary = exec(commandObjects.xgroupDestroy(key.getBytes(), groupName.getBytes())); + assertThat(xgroupDestroyBinary, equalTo(1L)); + + List groupInfoAfterBinary = exec(commandObjects.xinfoGroups(key)); + assertThat(groupInfoAfterBinary, empty()); + } + + @Test + public void testXGroupConsumer() { + String key = "testStream"; + String groupName = "testGroup"; + String consumerName = "testConsumer"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value"))); + + exec(commandObjects.xgroupCreate(key, groupName, initialId, false)); + + List groupIdBefore = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdBefore, hasSize(1)); + assertThat(groupIdBefore.get(0).getName(), equalTo(groupName)); + assertThat(groupIdBefore.get(0).getConsumers(), equalTo(0L)); + + Boolean createConsumer = exec(commandObjects.xgroupCreateConsumer(key, groupName, consumerName)); + assertThat(createConsumer, equalTo(true)); + + List groupIdAfterCreateConsumer = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfterCreateConsumer, hasSize(1)); + assertThat(groupIdAfterCreateConsumer.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfterCreateConsumer.get(0).getConsumers(), equalTo(1L)); + + Long deleteConsumer = exec(commandObjects.xgroupDelConsumer(key, groupName, consumerName)); + assertThat(deleteConsumer, equalTo(0L)); + + List groupIdAfterDeleteConsumer = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfterDeleteConsumer, hasSize(1)); + assertThat(groupIdAfterDeleteConsumer.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfterDeleteConsumer.get(0).getConsumers(), equalTo(0L)); + + Boolean createConsumerBinary = exec(commandObjects.xgroupCreateConsumer( + key.getBytes(), groupName.getBytes(), consumerName.getBytes())); + assertThat(createConsumerBinary, equalTo(true)); + + List groupIdAfterCreateConsumerBinary = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfterCreateConsumerBinary, hasSize(1)); + assertThat(groupIdAfterCreateConsumerBinary.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfterCreateConsumerBinary.get(0).getConsumers(), equalTo(1L)); + + Long deleteConsumerBinary = exec(commandObjects.xgroupDelConsumer( + key.getBytes(), groupName.getBytes(), consumerName.getBytes())); + assertThat(deleteConsumerBinary, equalTo(0L)); + + List groupIdAfterDeleteConsumerBinary = exec(commandObjects.xinfoGroups(key)); + + assertThat(groupIdAfterDeleteConsumerBinary, hasSize(1)); + assertThat(groupIdAfterDeleteConsumerBinary.get(0).getName(), equalTo(groupName)); + assertThat(groupIdAfterDeleteConsumerBinary.get(0).getConsumers(), equalTo(0L)); + } + + @Test + public void testXDelWithStreamSize() { + String key = "testStream"; + + StreamEntryID id1 = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field1", "value1"))); + StreamEntryID id2 = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field2", "value2"))); + + Long sizeBefore = exec(commandObjects.xlen(key)); + assertThat(sizeBefore, equalTo(2L)); + + Long xdel = exec(commandObjects.xdel(key, id1, id2)); + assertThat(xdel, equalTo(2L)); + + Long sizeAfterStringDeletion = exec(commandObjects.xlen(key)); + assertThat(sizeAfterStringDeletion, equalTo(0L)); + + StreamEntryID id3 = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field3", "value3"))); + StreamEntryID id4 = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field4", "value4"))); + + Long sizeBeforeBinaryDeletion = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeBinaryDeletion, equalTo(2L)); + + Long xdelBinary = exec(commandObjects.xdel( + key.getBytes(), id3.toString().getBytes(), id4.toString().getBytes())); + assertThat(xdelBinary, equalTo(2L)); + + Long sizeAfterBinaryDeletion = exec(commandObjects.xlen(key)); + assertThat(sizeAfterBinaryDeletion, equalTo(0L)); + } + + @Test + public void testXTrimCommands() { + String key = "testStream"; + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + } + + Long sizeBeforeTrim = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeTrim, equalTo(10L)); + + Long xtrim = exec(commandObjects.xtrim(key, 5, false)); + assertThat(xtrim, equalTo(5L)); + + Long sizeAfterTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterTrim, equalTo(5L)); + + // Repopulate the stream for byte[] parameter tests. + // Adding back 5 entries to ensure we have 10 again. + byte[] bKey = key.getBytes(); + for (int i = 5; i < 10; i++) { + exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + } + + Long sizeBeforeBinaryTrim = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeBinaryTrim, equalTo(10L)); + + Long xtrimBinary = exec(commandObjects.xtrim(bKey, 5, false)); + assertThat(xtrimBinary, equalTo(5L)); + + Long sizeAfterBinaryTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterBinaryTrim, equalTo(5L)); + } + + @Test + public void testXClaim() throws InterruptedException { + String key = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xgroupCreate(key, group, initialId, true)); + + StreamEntryID messageId = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value2"))); + + // Consumer1 reads the message to make it pending + Map stream = Collections.singletonMap(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + List>> readEntries = exec( + commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + assertThat(readEntries, hasSize(1)); + assertThat(readEntries.get(0).getKey(), equalTo(key)); + assertThat(readEntries.get(0).getValue(), hasSize(1)); + assertThat(readEntries.get(0).getValue().get(0).getID(), equalTo(messageId)); + + Thread.sleep(200); // Wait a bit + + // Claim the message for consumer2 + List claimedMessages = exec( + commandObjects.xclaim(key, group, consumer2, 1, new XClaimParams(), messageId)); + + assertThat(claimedMessages, hasSize(1)); + assertThat(claimedMessages.get(0).getID(), equalTo(messageId)); + } + + @Test + public void testXClaimBinary() throws InterruptedException { + String key = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xgroupCreate(key, group, initialId, true)); + + StreamEntryID messageId = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value2"))); + + // Consumer1 reads the message to make it pending + Map stream = Collections.singletonMap(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + List>> readEntries = exec( + commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + assertThat(readEntries, hasSize(1)); + assertThat(readEntries.get(0).getKey(), equalTo(key)); + assertThat(readEntries.get(0).getValue(), hasSize(1)); + assertThat(readEntries.get(0).getValue().get(0).getID(), equalTo(messageId)); + + Thread.sleep(200); // Wait a bit + + byte[] bMessageId = messageId.toString().getBytes(); + + // Claim the message for consumer2 + List claimedMessagesBytes = exec( + commandObjects.xclaim(key.getBytes(), group.getBytes(), consumer2.getBytes(), 1, new XClaimParams(), bMessageId)); + assertThat(claimedMessagesBytes, hasSize(1)); + // Good luck with asserting the content of this! + } + + @Test + public void testXClaimJustId() throws InterruptedException { + String key = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xgroupCreate(key, group, initialId, true)); + + StreamEntryID messageId = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value2"))); + + // Consumer1 reads the message to make it pending + Map stream = Collections.singletonMap(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + List>> readEntries = exec( + commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + assertThat(readEntries, hasSize(1)); + assertThat(readEntries.get(0).getKey(), equalTo(key)); + assertThat(readEntries.get(0).getValue(), hasSize(1)); + assertThat(readEntries.get(0).getValue().get(0).getID(), equalTo(messageId)); + + Thread.sleep(200); // Wait a bit + + // Claim the message for consumer2 with String parameters + List claimedMessagesString = exec( + commandObjects.xclaimJustId(key, group, consumer2, 1, new XClaimParams(), messageId)); + assertThat(claimedMessagesString, hasSize(1)); + assertThat(claimedMessagesString.get(0), equalTo(messageId)); + } + + @Test + public void testXClaimJustIdBinary() throws InterruptedException { + String key = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + StreamEntryID initialId = new StreamEntryID(); + + exec(commandObjects.xgroupCreate(key, group, initialId, true)); + + StreamEntryID messageId = exec(commandObjects.xadd(key, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field", "value2"))); + + // Consumer1 reads the message to make it pending + Map stream = Collections.singletonMap(key, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + List>> readEntries = exec( + commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + assertThat(readEntries, hasSize(1)); + assertThat(readEntries.get(0).getKey(), equalTo(key)); + assertThat(readEntries.get(0).getValue(), hasSize(1)); + assertThat(readEntries.get(0).getValue().get(0).getID(), equalTo(messageId)); + + Thread.sleep(200); // Wait a bit + + byte[] bMessageId = messageId.toString().getBytes(); + + // Claim the message for consumer2 with byte[] parameters + List claimedMessagesBytes = exec( + commandObjects.xclaimJustId(key.getBytes(), group.getBytes(), consumer2.getBytes(), 1, new XClaimParams(), bMessageId)); + assertThat(claimedMessagesBytes, hasSize(1)); + // Good luck with asserting the content of this! + } + + @Test + public void testXAutoClaim() throws InterruptedException { + String streamKey = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); + + Map messageBody = Collections.singletonMap("field", "value"); + StreamEntryID initialEntryId = exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + + Map stream = Collections.singletonMap(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + exec(commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + Thread.sleep(200); // Wait a bit + + StreamEntryID startId = new StreamEntryID(initialEntryId.getTime() - 1, initialEntryId.getSequence()); + XAutoClaimParams params = new XAutoClaimParams().count(1); + + // Auto claim message for consumer2 + Map.Entry> autoClaimResult = exec( + commandObjects.xautoclaim(streamKey, group, consumer2, 1, startId, params)); + + assertThat(autoClaimResult.getValue(), hasSize(1)); + assertThat(autoClaimResult.getValue().get(0).getFields(), equalTo(messageBody)); + } + + @Test + public void testXAutoClaimBinary() throws InterruptedException { + byte[] streamKey = "testStream".getBytes(); + byte[] group = "testGroup".getBytes(); + byte[] consumer1 = "consumer1".getBytes(); + byte[] consumer2 = "consumer2".getBytes(); + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID().toString().getBytes(), true)); + + Map messageBody = Collections.singletonMap("field".getBytes(), "value".getBytes()); + byte[] initialEntryId = exec(commandObjects.xadd(streamKey, new XAddParams(), messageBody)); + + Map.Entry entry = new AbstractMap.SimpleEntry<>(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY.toString().getBytes()); + exec(commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), entry)); + + Thread.sleep(200); // Wait a bit + + StreamEntryID initialStreamEntryID = new StreamEntryID(new String(initialEntryId)); + byte[] startId = new StreamEntryID(initialStreamEntryID.getTime() - 1, 0).toString().getBytes(); + XAutoClaimParams params = new XAutoClaimParams().count(1); + + // Auto claim message for consumer2 in binary + List autoClaimResultBinary = exec(commandObjects.xautoclaim(streamKey, group, consumer2, 1, startId, params)); + assertThat(autoClaimResultBinary, not(empty())); + } + + @Test + public void testXAutoClaimJustId() throws InterruptedException { + String streamKey = "testStream"; + String group = "testGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); + + Map messageBody = Collections.singletonMap("fieldSingle", "valueSingle"); + StreamEntryID initialEntryId = exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + + Map stream = Collections.singletonMap(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + exec(commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + Thread.sleep(200); // Wait a bit + + StreamEntryID startId = new StreamEntryID(initialEntryId.getTime() - 1, initialEntryId.getSequence()); + XAutoClaimParams params = new XAutoClaimParams().count(1); + + Map.Entry> autoClaimResult = exec( + commandObjects.xautoclaimJustId(streamKey, group, consumer2, 1, startId, params)); + + assertThat(autoClaimResult.getValue(), hasSize(1)); + assertThat(autoClaimResult.getValue().get(0), equalTo(initialEntryId)); + } + + @Test + public void testXAutoClaimJustIdBinary() throws InterruptedException { + byte[] streamKey = "testStream".getBytes(); + byte[] group = "testGroup".getBytes(); + byte[] consumer1 = "consumer1".getBytes(); + byte[] consumer2 = "consumer2".getBytes(); + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID().toString().getBytes(), true)); + + Map messageBody = Collections.singletonMap("fieldBinary".getBytes(), "valueBinary".getBytes()); + byte[] initialEntryId = exec(commandObjects.xadd(streamKey, new XAddParams(), messageBody)); + + Map.Entry stream = new AbstractMap.SimpleEntry<>(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY.toString().getBytes()); + exec(commandObjects.xreadGroup(group, consumer1, new XReadGroupParams().count(1), stream)); + + Thread.sleep(200); // Wait a bit + + StreamEntryID initialStreamEntryID = new StreamEntryID(new String(initialEntryId)); + byte[] startId = new StreamEntryID(initialStreamEntryID.getTime() - 1, 0).toString().getBytes(); + XAutoClaimParams params = new XAutoClaimParams().count(1); + + List autoClaimResultBinary = exec( + commandObjects.xautoclaimJustId(streamKey, group, consumer2, 1, startId, params)); + assertThat(autoClaimResultBinary, not(empty())); + } + + @Test + public void testXInfoStream() { + String streamKey = "testStreamInfo"; + + Map messageBody = Collections.singletonMap("fieldInfo", "valueInfo"); + + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + + StreamInfo streamInfo = exec(commandObjects.xinfoStream(streamKey)); + + assertThat(streamInfo, notNullValue()); + assertThat(streamInfo.getLength(), equalTo(1L)); + assertThat(streamInfo.getFirstEntry().getFields(), equalTo(messageBody)); + + Object streamInfoBinary = exec(commandObjects.xinfoStream(streamKey.getBytes())); + assertThat(streamInfoBinary, notNullValue()); + } + + @Test + public void testXInfoStreamFull() { + String streamKey = "testStreamFullInfo"; + + Map messageBody = Collections.singletonMap("fieldFull", "valueFull"); + + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + + StreamFullInfo streamFullInfo = exec(commandObjects.xinfoStreamFull(streamKey)); + + assertThat(streamFullInfo, notNullValue()); + assertThat(streamFullInfo.getEntries(), not(empty())); + assertThat(streamFullInfo.getEntries().get(0).getFields(), equalTo(messageBody)); + + StreamFullInfo streamFullInfoWithCount = exec(commandObjects.xinfoStreamFull(streamKey, 1)); + assertThat(streamFullInfoWithCount, notNullValue()); + assertThat(streamFullInfoWithCount.getEntries(), hasSize(1)); + + Object streamInfoBinaryFull = exec(commandObjects.xinfoStreamFull(streamKey.getBytes())); + assertThat(streamInfoBinaryFull, notNullValue()); + + Object streamInfoBinaryFullWithCount = exec(commandObjects.xinfoStreamFull(streamKey.getBytes(), 1)); + assertThat(streamInfoBinaryFullWithCount, notNullValue()); + } + + @Test + @Deprecated + public void testXInfoConsumersWithActiveConsumers() { + String streamKey = "testStreamWithConsumers"; + String group = "testConsumerGroup"; + String consumer1 = "consumer1"; + String consumer2 = "consumer2"; + + Map messageBody1 = Collections.singletonMap("field1", "value1"); + Map messageBody2 = Collections.singletonMap("field2", "value2"); + + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody1)); + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody2)); + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); + + XReadGroupParams xReadGroupParams = new XReadGroupParams().count(1); + Map stream = Collections.singletonMap(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + exec(commandObjects.xreadGroup(group, consumer1, xReadGroupParams, stream)); + exec(commandObjects.xreadGroup(group, consumer2, xReadGroupParams, stream)); + + List consumersInfoList = exec(commandObjects.xinfoConsumers(streamKey, group)); + assertThat(consumersInfoList, notNullValue()); + assertThat(consumersInfoList, hasSize(2)); + + Optional consumersInfo1 = consumersInfoList.stream().filter(c -> c.getName().equals(consumer1)).findFirst(); + Optional consumersInfo2 = consumersInfoList.stream().filter(c -> c.getName().equals(consumer2)).findFirst(); + + assertThat(consumersInfo1.isPresent(), equalTo(true)); + assertThat(consumersInfo1.get().getPending(), equalTo(1L)); + + assertThat(consumersInfo2.isPresent(), equalTo(true)); + assertThat(consumersInfo2.get().getPending(), equalTo(1L)); + + List consumerInfoList = exec(commandObjects.xinfoConsumers2(streamKey, group)); + assertThat(consumerInfoList, notNullValue()); + assertThat(consumerInfoList, hasSize(2)); + + Optional consumerInfo1 = consumerInfoList.stream().filter(c -> c.getName().equals(consumer1)).findFirst(); + Optional consumerInfo2 = consumerInfoList.stream().filter(c -> c.getName().equals(consumer2)).findFirst(); + + assertThat(consumerInfo1.isPresent(), equalTo(true)); + assertThat(consumerInfo1.get().getPending(), equalTo(1L)); + + assertThat(consumerInfo2.isPresent(), equalTo(true)); + assertThat(consumerInfo2.get().getPending(), equalTo(1L)); + + List consumersInfoBinary = exec(commandObjects.xinfoConsumers(streamKey.getBytes(), group.getBytes())); + assertThat(consumersInfoBinary, notNullValue()); + } + + @Test + public void testXRead() { + String streamKey1 = "testStream1"; + String streamKey2 = "testStream2"; + + Map messageBody1 = Collections.singletonMap("field1", "value1"); + Map messageBody2 = Collections.singletonMap("field2", "value2"); + + StreamEntryID messageId1 = exec(commandObjects.xadd(streamKey1, StreamEntryID.NEW_ENTRY, messageBody1)); + StreamEntryID messageId2 = exec(commandObjects.xadd(streamKey2, StreamEntryID.NEW_ENTRY, messageBody2)); + + XReadParams params = XReadParams.xReadParams().count(1).block(1000); + Map streams = new HashMap<>(); + streams.put(streamKey1, new StreamEntryID()); + streams.put(streamKey2, new StreamEntryID()); + + List>> xread = exec(commandObjects.xread(params, streams)); + + assertThat(xread, not(empty())); + assertThat(xread.size(), equalTo(2)); + assertThat(xread.get(0).getKey(), equalTo(streamKey1)); + assertThat(xread.get(1).getKey(), equalTo(streamKey2)); + assertThat(xread.get(0).getValue().get(0).getID(), equalTo(messageId1)); + assertThat(xread.get(1).getValue().get(0).getID(), equalTo(messageId2)); + assertThat(xread.get(0).getValue().get(0).getFields(), equalTo(messageBody1)); + assertThat(xread.get(1).getValue().get(0).getFields(), equalTo(messageBody2)); + + byte[] streamKey1Binary = streamKey1.getBytes(); + byte[] streamKey2Binary = streamKey2.getBytes(); + Map.Entry stream1 = new AbstractMap.SimpleEntry<>(streamKey1Binary, new StreamEntryID().toString().getBytes()); + Map.Entry stream2 = new AbstractMap.SimpleEntry<>(streamKey2Binary, new StreamEntryID().toString().getBytes()); + + List xreadBinary = exec(commandObjects.xread(params, stream1, stream2)); + assertThat(xreadBinary, not(empty())); + } + + @Test + public void testXReadAsMap() { + String streamKey1 = "testStreamMap1"; + String streamKey2 = "testStreamMap2"; + + Map messageBody1 = Collections.singletonMap("fieldMap1", "valueMap1"); + Map messageBody2 = Collections.singletonMap("fieldMap2", "valueMap2"); + + exec(commandObjects.xadd(streamKey1, StreamEntryID.NEW_ENTRY, messageBody1)); + exec(commandObjects.xadd(streamKey2, StreamEntryID.NEW_ENTRY, messageBody2)); + + XReadParams params = new XReadParams().count(1).block(1000); + + Map streams = new HashMap<>(); + streams.put(streamKey1, new StreamEntryID()); + streams.put(streamKey2, new StreamEntryID()); + + Map> xreadAsMap = exec(commandObjects.xreadAsMap(params, streams)); + assertThat(xreadAsMap, notNullValue()); + assertThat(xreadAsMap.keySet(), hasSize(2)); // Expecting keys for both streams + assertThat(xreadAsMap.get(streamKey1).get(0).getFields(), equalTo(messageBody1)); + assertThat(xreadAsMap.get(streamKey2).get(0).getFields(), equalTo(messageBody2)); + } + + @Test + public void testXReadGroupAsMap() { + String streamKey = "testStreamGroupMap"; + String group = "testGroupMap"; + String consumer1 = "testConsumerMap1"; + String consumer2 = "testConsumerMap2"; + + Map messageBody = Collections.singletonMap("fieldGroupMap", "valueGroupMap"); + + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); + + StreamEntryID initialMessageId = exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + StreamEntryID secondMessageId = exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody)); + + XReadGroupParams params = new XReadGroupParams().count(1); + + Map streams = new HashMap<>(); + streams.put(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); + + Map> xreadGroupConsumer1 = exec(commandObjects.xreadGroupAsMap(group, consumer1, params, streams)); + + assertThat(xreadGroupConsumer1, notNullValue()); + assertThat(xreadGroupConsumer1.keySet(), hasSize(1)); + assertThat(xreadGroupConsumer1.get(streamKey), not(empty())); + assertThat(xreadGroupConsumer1.get(streamKey).get(0).getID(), equalTo(initialMessageId)); + assertThat(xreadGroupConsumer1.get(streamKey).get(0).getFields(), equalTo(messageBody)); + + Map> xreadGroupConsumer2 = exec(commandObjects.xreadGroupAsMap(group, consumer2, params, streams)); + + assertThat(xreadGroupConsumer2, notNullValue()); + assertThat(xreadGroupConsumer2.keySet(), hasSize(1)); // Expecting keys for the stream + assertThat(xreadGroupConsumer2.get(streamKey), not(empty())); // Expecting at least one message + assertThat(xreadGroupConsumer2.get(streamKey).get(0).getID(), equalTo(secondMessageId)); + assertThat(xreadGroupConsumer2.get(streamKey).get(0).getFields(), equalTo(messageBody)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java new file mode 100644 index 0000000000..9a35cd88e4 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java @@ -0,0 +1,593 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.nullValue; + +import java.util.List; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.params.GetExParams; +import redis.clients.jedis.params.LCSParams; +import redis.clients.jedis.params.SetParams; +import redis.clients.jedis.resps.LCSMatchResult; + +/** + * Tests related to String commands. + */ +public class CommandObjectsStringCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsStringCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testAppend() { + String key = "testKey"; + String value = "testValue"; + + String initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, nullValue()); + + Long append = exec(commandObjects.append(key, value)); + assertThat(append, equalTo((long) value.length())); + + String getAfterAppend = exec(commandObjects.get(key)); + assertThat(getAfterAppend, equalTo(value)); + + Long secondAppend = exec(commandObjects.append(key, value)); + assertThat(secondAppend, equalTo((long) value.length() * 2)); + + String getAfterSecondAppend = exec(commandObjects.get(key)); + assertThat(getAfterSecondAppend, equalTo(value + value)); + } + + @Test + public void testAppendBinary() { + byte[] key = "testKeyBytes".getBytes(); + byte[] value = "testValueBytes".getBytes(); + + byte[] initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, nullValue()); + + Long append = exec(commandObjects.append(key, value)); + assertThat(append, equalTo((long) value.length)); + + byte[] getAfterAppend = exec(commandObjects.get(key)); + assertThat(getAfterAppend, equalTo(value)); + + Long secondAppend = exec(commandObjects.append(key, value)); + assertThat(secondAppend, equalTo((long) value.length * 2)); + + byte[] getAfterSecondAppend = exec(commandObjects.get(key)); + + byte[] expected = new byte[value.length + value.length]; + System.arraycopy(value, 0, expected, 0, value.length); + System.arraycopy(value, 0, expected, value.length, value.length); + + assertThat(getAfterSecondAppend, equalTo(expected)); + } + + @Test + public void testDecrementOperations() { + String key = "testDecr"; + + exec(commandObjects.set(key, String.valueOf(10L))); + + String initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo("10")); + + Long decr = exec(commandObjects.decr(key)); + assertThat(decr, equalTo(9L)); + + String getAfterDecr = exec(commandObjects.get(key)); + assertThat(getAfterDecr, equalTo("9")); + + Long decrBy = exec(commandObjects.decrBy(key, 2L)); + assertThat(decrBy, equalTo(7L)); + + String getAfterDecrBy = exec(commandObjects.get(key)); + assertThat(getAfterDecrBy, equalTo("7")); + } + + @Test + public void testDecrementOperationsBinary() { + byte[] key = "testDecrBytes".getBytes(); + + exec(commandObjects.set(key, String.valueOf(10L).getBytes())); + + byte[] initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo("10".getBytes())); + + Long decr = exec(commandObjects.decr(key)); + assertThat(decr, equalTo(9L)); + + byte[] getAfterDecr = exec(commandObjects.get(key)); + assertThat(getAfterDecr, equalTo("9".getBytes())); + + Long decrBy = exec(commandObjects.decrBy(key, 2L)); + assertThat(decrBy, equalTo(7L)); + + byte[] getAfterDecrBy = exec(commandObjects.get(key)); + assertThat(getAfterDecrBy, equalTo("7".getBytes())); + } + + @Test + public void testGetOperations() { + String key = "testGet"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + String initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo(value)); + + String getDel = exec(commandObjects.getDel(key)); + assertThat(getDel, equalTo(value)); + + String getAfterGetDel = exec(commandObjects.get(key)); + assertThat(getAfterGetDel, nullValue()); + + // set again + exec(commandObjects.set(key, value)); + + Long initialTtl = exec(commandObjects.ttl(key)); + assertThat(initialTtl, equalTo(-1L)); + + GetExParams getExParams = GetExParams.getExParams().ex(10); + String getEx = exec(commandObjects.getEx(key, getExParams)); + assertThat(getEx, equalTo(value)); + + Long ttlAfterGetEx = exec(commandObjects.ttl(key)); + assertThat(ttlAfterGetEx, greaterThan(0L)); + } + + @Test + public void testGetOperationsBinary() { + byte[] key = "testGetBytes".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + byte[] initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo(value)); + + byte[] getDel = exec(commandObjects.getDel(key)); + assertThat(getDel, equalTo(value)); + + byte[] getAfterGetDel = exec(commandObjects.get(key)); + assertThat(getAfterGetDel, nullValue()); + + // set again + exec(commandObjects.set(key, value)); + + Long initialTtl = exec(commandObjects.ttl(key)); + assertThat(initialTtl, equalTo(-1L)); + + GetExParams getExParams = GetExParams.getExParams().ex(10); + byte[] getEx = exec(commandObjects.getEx(key, getExParams)); + assertThat(getEx, equalTo(value)); + + Long ttlAfterGetEx = exec(commandObjects.ttl(key)); + assertThat(ttlAfterGetEx, greaterThan(0L)); + } + + @Test + @Deprecated + public void testGetSet() { + String key = "testGetSet"; + String initialValue = "initialValue"; + String newValue = "newValue"; + + exec(commandObjects.set(key, initialValue)); + + String initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo(initialValue)); + + String getSet = exec(commandObjects.getSet(key, newValue)); + assertThat(getSet, equalTo(initialValue)); + + String getAfterGetSet = exec(commandObjects.get(key)); + assertThat(getAfterGetSet, equalTo(newValue)); + } + + @Test + @Deprecated + public void testGetSetBinary() { + byte[] key = "testGetSetBytes".getBytes(); + byte[] initialValue = "initialValue".getBytes(); + byte[] newValue = "newValue".getBytes(); + + exec(commandObjects.set(key, initialValue)); + + byte[] initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo(initialValue)); + + byte[] getSet = exec(commandObjects.getSet(key, newValue)); + assertThat(getSet, equalTo(initialValue)); + + byte[] getAfterGetSet = exec(commandObjects.get(key)); + assertThat(getAfterGetSet, equalTo(newValue)); + } + + @Test + public void testSetRangeAndGetRange() { + String key = "testRange"; + String initial = "Hello World"; + String replacement = "Everyone"; + long replacementOffset = 6L; + + exec(commandObjects.set(key, initial)); + + Long setRange = exec(commandObjects.setrange(key, replacementOffset, replacement)); + assertThat(setRange, equalTo(14L)); // Length after replacement + + String getRange = exec(commandObjects.getrange(key, 0, -1)); + assertThat(getRange, equalTo("Hello Everyone")); + } + + @Test + public void testSetRangeAndGetRangeBinary() { + byte[] key = "testRangeBytes".getBytes(); + byte[] initialValue = "Hello World".getBytes(); + byte[] replacement = "Everyone".getBytes(); + long replacementOffset = 6L; + + exec(commandObjects.set(key, initialValue)); + + Long setRange = exec(commandObjects.setrange(key, replacementOffset, replacement)); + assertThat(setRange, equalTo(14L)); // Length after replacement + + byte[] getRange = exec(commandObjects.getrange(key, 0, -1)); + assertThat(getRange, equalTo("Hello Everyone".getBytes())); + } + + @Test + public void testIncrementOperations() { + String key = "testIncr"; + + exec(commandObjects.set(key, "0")); + + Long incr = exec(commandObjects.incr(key)); + assertThat(incr, equalTo(1L)); + + String getAfterIncr = exec(commandObjects.get(key)); + assertThat(getAfterIncr, equalTo("1")); + + Long incrBy = exec(commandObjects.incrBy(key, 5L)); + assertThat(incrBy, equalTo(6L)); + + String getAfterIncrBy = exec(commandObjects.get(key)); + assertThat(getAfterIncrBy, equalTo("6")); + + Double incrByFloat = exec(commandObjects.incrByFloat(key, 2.5)); + assertThat(incrByFloat, closeTo(8.5, 0.001)); + + String getAfterIncrByFloat = exec(commandObjects.get(key)); + assertThat(getAfterIncrByFloat, equalTo("8.5")); + } + + @Test + public void testIncrementOperationsBinary() { + byte[] key = "testIncrBytes".getBytes(); + + exec(commandObjects.set(key, "0".getBytes())); + + Long incr = exec(commandObjects.incr(key)); + assertThat(incr, equalTo(1L)); + + byte[] getAfterIncr = exec(commandObjects.get(key)); + assertThat(getAfterIncr, equalTo("1".getBytes())); + + Long incrBy = exec(commandObjects.incrBy(key, 5L)); + assertThat(incrBy, equalTo(6L)); + + byte[] getAfterIncrBy = exec(commandObjects.get(key)); + assertThat(getAfterIncrBy, equalTo("6".getBytes())); + + Double incrByFloat = exec(commandObjects.incrByFloat(key, 2.5)); + assertThat(incrByFloat, closeTo(8.5, 0.001)); + + byte[] getAfterIncrByFloat = exec(commandObjects.get(key)); + assertThat(getAfterIncrByFloat, equalTo("8.5".getBytes())); + } + + @Test + public void testLcs() { + String keyA = "keyA"; + String keyB = "keyB"; + + // "abcdfg" is the common substring + String valueA = "abcdfgh"; + String valueB = "abcdefg"; + + exec(commandObjects.set(keyA, valueA)); + exec(commandObjects.set(keyB, valueB)); + + LCSMatchResult lcsLen = exec(commandObjects.lcs(keyA, keyB, new LCSParams().len())); + assertThat(lcsLen.getLen(), equalTo(6L)); + assertThat(lcsLen.getMatchString(), nullValue()); + + LCSMatchResult lcs = exec(commandObjects.lcs(keyA, keyB, new LCSParams())); + assertThat(lcs.getLen(), equalTo(0L)); + assertThat(lcs.getMatchString(), equalTo("abcdfg")); + + LCSMatchResult lcsMatches = exec(commandObjects.lcs(keyA, keyB, new LCSParams().idx().withMatchLen())); + assertThat(lcsMatches.getLen(), equalTo(6L)); + assertThat(lcsMatches.getMatchString(), nullValue()); + assertThat(lcsMatches.getMatches(), hasSize(2)); + + LCSMatchResult.MatchedPosition match1 = lcsMatches.getMatches().get(0); + assertThat(match1.getMatchLen(), equalTo(2L)); + assertThat(match1.getA().getStart(), equalTo(4L)); + assertThat(match1.getA().getEnd(), equalTo(5L)); + assertThat(match1.getB().getStart(), equalTo(5L)); + assertThat(match1.getB().getEnd(), equalTo(6L)); + + LCSMatchResult.MatchedPosition match2 = lcsMatches.getMatches().get(1); + assertThat(match2.getMatchLen(), equalTo(4L)); + assertThat(match2.getA().getStart(), equalTo(0L)); + assertThat(match2.getA().getEnd(), equalTo(3L)); + assertThat(match2.getB().getStart(), equalTo(0L)); + assertThat(match2.getB().getEnd(), equalTo(3L)); + } + + @Test + public void testLcsBinary() { + byte[] keyA = "keyA".getBytes(); + byte[] keyB = "keyB".getBytes(); + + // "abcdfg" is the common substring + String valueA = "abcdfgh"; + String valueB = "abcdefg"; + + exec(commandObjects.set(keyA, valueA.getBytes())); + exec(commandObjects.set(keyB, valueB.getBytes())); + + LCSMatchResult lcsLen = exec(commandObjects.lcs(keyA, keyB, new LCSParams().len())); + assertThat(lcsLen.getLen(), equalTo(6L)); + assertThat(lcsLen.getMatchString(), nullValue()); + + LCSMatchResult lcs = exec(commandObjects.lcs(keyA, keyB, new LCSParams())); + assertThat(lcs.getLen(), equalTo(0L)); + assertThat(lcs.getMatchString(), equalTo("abcdfg")); + + LCSMatchResult lcsMatches = exec(commandObjects.lcs(keyA, keyB, new LCSParams().idx().withMatchLen())); + assertThat(lcsMatches.getLen(), equalTo(6L)); + assertThat(lcsMatches.getMatchString(), nullValue()); + assertThat(lcsMatches.getMatches(), hasSize(2)); + + LCSMatchResult.MatchedPosition match1 = lcsMatches.getMatches().get(0); + assertThat(match1.getMatchLen(), equalTo(2L)); + assertThat(match1.getA().getStart(), equalTo(4L)); + assertThat(match1.getA().getEnd(), equalTo(5L)); + assertThat(match1.getB().getStart(), equalTo(5L)); + assertThat(match1.getB().getEnd(), equalTo(6L)); + + LCSMatchResult.MatchedPosition match2 = lcsMatches.getMatches().get(1); + assertThat(match2.getMatchLen(), equalTo(4L)); + assertThat(match2.getA().getStart(), equalTo(0L)); + assertThat(match2.getA().getEnd(), equalTo(3L)); + assertThat(match2.getB().getStart(), equalTo(0L)); + assertThat(match2.getB().getEnd(), equalTo(3L)); + } + + @Test + public void testMgetMsetAndMsetnx() { + String key1 = "key1"; + String key2 = "key2"; + + String mset = exec(commandObjects.mset(key1, "value1", key2, "value2")); + assertThat(mset, equalTo("OK")); + + List mget = exec(commandObjects.mget(key1, key2)); + assertThat(mget, contains("value1", "value2")); + + Long msetNx = exec(commandObjects.msetnx(key1, "new1", key2, "new2")); + assertThat(msetNx, equalTo(0L)); + + List mgetAfterMsetNx = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterMsetNx, contains("value1", "value2")); + + Long del = exec(commandObjects.del(key1, key2)); + assertThat(del, equalTo(2L)); + + List mgetAfterDel = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterDel, contains(nullValue(), nullValue())); + + Long msetNxAfterDel = exec(commandObjects.msetnx(key1, "new1", key2, "new2")); + assertThat(msetNxAfterDel, equalTo(1L)); + + List mgetAfterMsetNxAfterDel = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterMsetNxAfterDel, contains("new1", "new2")); + } + + @Test + public void testMgetMsetAndMsetnxBinary() { + byte[] key1 = "key1Bytes".getBytes(); + byte[] key2 = "key2Bytes".getBytes(); + + String mset = exec(commandObjects.mset(key1, "value1".getBytes(), key2, "value2".getBytes())); + assertThat(mset, equalTo("OK")); + + List mget = exec(commandObjects.mget(key1, key2)); + assertThat(mget, contains("value1".getBytes(), "value2".getBytes())); + + Long msetNx = exec(commandObjects.msetnx(key1, "new1".getBytes(), key2, "new2".getBytes())); + assertThat(msetNx, equalTo(0L)); + + List mgetAfterMsetNx = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterMsetNx, contains("value1".getBytes(), "value2".getBytes())); + + Long del = exec(commandObjects.del(key1, key2)); + assertThat(del, equalTo(2L)); + + List mgetAfterDel = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterDel, contains(nullValue(), nullValue())); + + Long msetNxAfterDel = exec(commandObjects.msetnx(key1, "new1".getBytes(), key2, "new2".getBytes())); + assertThat(msetNxAfterDel, equalTo(1L)); + + List mgetAfterMsetNxAfterDel = exec(commandObjects.mget(key1, key2)); + assertThat(mgetAfterMsetNxAfterDel, contains("new1".getBytes(), "new2".getBytes())); + } + + @Test + public void testPsetexPttl() { + String key = "tempKey"; + long milliseconds = 1000L; + + String psetEx = exec(commandObjects.psetex(key, milliseconds, "tempValue")); + assertThat(psetEx, equalTo("OK")); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(0L)); + } + + @Test + public void testPsetexPttlBinary() { + byte[] key = "tempKey".getBytes(); + long milliseconds = 1000L; + + String psetEx = exec(commandObjects.psetex(key, milliseconds, "tempValue".getBytes())); + assertThat(psetEx, equalTo("OK")); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(0L)); + } + + @Test + public void testSetAndSetGet() { + String key = "myKey"; + + String set = exec(commandObjects.set(key, "firstValue")); + assertThat(set, equalTo("OK")); + + String initialGet = exec(commandObjects.get(key)); + assertThat(initialGet, equalTo("firstValue")); + + SetParams setParams = new SetParams().ex(10); + String setWithParams = exec(commandObjects.set(key, "secondValue", setParams)); + assertThat(setWithParams, equalTo("OK")); + + String getAfterSetWithParams = exec(commandObjects.get(key)); + assertThat(getAfterSetWithParams, equalTo("secondValue")); + + String setGet = exec(commandObjects.setGet(key, "thirdValue")); + assertThat(setGet, equalTo("secondValue")); + + String getAfterSetGet = exec(commandObjects.get(key)); + assertThat(getAfterSetGet, equalTo("thirdValue")); + + String setGetWithParams = exec(commandObjects.setGet(key, "finalValue", setParams)); + assertThat(setGetWithParams, equalTo("thirdValue")); + + String finalGet = exec(commandObjects.get(key)); + assertThat(finalGet, equalTo("finalValue")); + } + + @Test + public void testSetAndSetGetBinary() { + byte[] key = "myKeyBytes".getBytes(); + + String set = exec(commandObjects.set(key, "firstValue".getBytes())); + assertThat(set, equalTo("OK")); + + byte[] getAfterSet = exec(commandObjects.get(key)); + assertThat(getAfterSet, equalTo("firstValue".getBytes())); + + SetParams setParams = new SetParams().ex(10); + String setWithParams = exec(commandObjects.set(key, "secondValue".getBytes(), setParams)); + assertThat(setWithParams, equalTo("OK")); + + byte[] getAfterSetWithParams = exec(commandObjects.get(key)); + assertThat(getAfterSetWithParams, equalTo("secondValue".getBytes())); + + byte[] setGet = exec(commandObjects.setGet(key, "thirdValue".getBytes())); + assertThat(setGet, equalTo("secondValue".getBytes())); + + byte[] getAfterSetGet = exec(commandObjects.get(key)); + assertThat(getAfterSetGet, equalTo("thirdValue".getBytes())); + + byte[] setGetWithParams = exec(commandObjects.setGet(key, "finalValue".getBytes(), setParams)); + assertThat(setGetWithParams, equalTo("thirdValue".getBytes())); + + byte[] getAfterSetGetWithParams = exec(commandObjects.get(key)); + assertThat(getAfterSetGetWithParams, equalTo("finalValue".getBytes())); + } + + @Test + public void testSetnxAndSetexWithGets() { + String key = "uniqueKey"; + + Long setNx = exec(commandObjects.setnx(key, "helloWorld")); + assertThat(setNx, equalTo(1L)); + + String getAfterSetNx = exec(commandObjects.get(key)); + assertThat(getAfterSetNx, equalTo("helloWorld")); + + String setEx = exec(commandObjects.setex(key, 10L, "newValue")); + assertThat(setEx, equalTo("OK")); + + String getAfterSetEx = exec(commandObjects.get(key)); + assertThat(getAfterSetEx, equalTo("newValue")); + + Long setNxAgain = exec(commandObjects.setnx(key, "anotherNewValue")); + assertThat(setNxAgain, equalTo(0L)); + + String getAfterSetNxAgain = exec(commandObjects.get(key)); + assertThat(getAfterSetNxAgain, equalTo("newValue")); + } + + @Test + public void testSetnxAndSetexWithGetsBinary() { + byte[] key = "uniqueKeyBytes".getBytes(); + + Long setNx = exec(commandObjects.setnx(key, "helloWorld".getBytes())); + assertThat(setNx, equalTo(1L)); + + byte[] getAfterSetNx = exec(commandObjects.get(key)); + assertThat(getAfterSetNx, equalTo("helloWorld".getBytes())); + + String setEx = exec(commandObjects.setex(key, 10L, "newValue".getBytes())); + assertThat(setEx, equalTo("OK")); + + byte[] getAfterSetEx = exec(commandObjects.get(key)); + assertThat(getAfterSetEx, equalTo("newValue".getBytes())); + + Long setNxAgain = exec(commandObjects.setnx(key, "anotherNewValueBytes".getBytes())); + assertThat(setNxAgain, equalTo(0L)); + + byte[] getAfterSetNxAgain = exec(commandObjects.get(key)); + assertThat(getAfterSetNxAgain, equalTo("newValue".getBytes())); + } + + @Test + public void testSubstrAndStrlen() { + String key = "testKey"; + String value = "HelloWorld"; + + int start = 1; + int end = 5; // end is inclusive + String fragment = "elloW"; + + exec(commandObjects.set(key, value)); + + String substr = exec(commandObjects.substr(key, start, end)); + assertThat(substr, equalTo(fragment)); + + byte[] substrBinary = exec(commandObjects.substr(key.getBytes(), start, end)); + assertThat(substrBinary, equalTo(fragment.getBytes())); + + Long strlen = exec(commandObjects.strlen(key)); + assertThat(strlen, equalTo((long) value.length())); + + Long strlenBinary = exec(commandObjects.strlen(key.getBytes())); + assertThat(strlenBinary, equalTo((long) value.length())); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTDigestCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTDigestCommandsTest.java new file mode 100644 index 0000000000..f16bc91abb --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTDigestCommandsTest.java @@ -0,0 +1,255 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.notANumber; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.bloom.TDigestMergeParams; + +/** + * Tests related to T-Digest commands. + */ +public class CommandObjectsTDigestCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsTDigestCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testTDigestAddMinMax() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0, 4.0, 5.0)); + assertThat(add, equalTo("OK")); + + Double minValue = exec(commandObjects.tdigestMin(key)); + assertThat(minValue, equalTo(1.0)); + + Double maxValue = exec(commandObjects.tdigestMax(key)); + assertThat(maxValue, equalTo(5.0)); + } + + @Test + public void testTDigestMerge() { + String destinationKey = "testTDigestMergeDest"; + String sourceKey1 = "testTDigestSource1"; + String sourceKey2 = "testTDigestSource2"; + + String create1 = exec(commandObjects.tdigestCreate(sourceKey1)); + assertThat(create1, equalTo("OK")); + + String create2 = exec(commandObjects.tdigestCreate(sourceKey2)); + assertThat(create2, equalTo("OK")); + + String add1 = exec(commandObjects.tdigestAdd(sourceKey1, 1.0, 2.0)); + assertThat(add1, equalTo("OK")); + + String add2 = exec(commandObjects.tdigestAdd(sourceKey2, 3.0, 4.0)); + assertThat(add2, equalTo("OK")); + + String merge = exec(commandObjects.tdigestMerge(destinationKey, sourceKey1, sourceKey2)); + assertThat(merge, equalTo("OK")); + + Double minAfterMerge = exec(commandObjects.tdigestMin(destinationKey)); + assertThat(minAfterMerge, equalTo(1.0)); + + Double maxAfterMerge = exec(commandObjects.tdigestMax(destinationKey)); + assertThat(maxAfterMerge, equalTo(4.0)); + } + + @Test + public void testTDigestMergeWithParams() { + String destinationKey = "testTDigestMergeDestParams"; + String sourceKey1 = "testTDigestSource1Params"; + String sourceKey2 = "testTDigestSource2Params"; + + TDigestMergeParams mergeParams = new TDigestMergeParams().compression(100); + + String create1 = exec(commandObjects.tdigestCreate(sourceKey1, 100)); + assertThat(create1, equalTo("OK")); + + String create2 = exec(commandObjects.tdigestCreate(sourceKey2, 100)); + assertThat(create2, equalTo("OK")); + + String add1 = exec(commandObjects.tdigestAdd(sourceKey1, 10.0, 20.0)); + assertThat(add1, equalTo("OK")); + + String add2 = exec(commandObjects.tdigestAdd(sourceKey2, 30.0, 40.0)); + assertThat(add2, equalTo("OK")); + + String merge = exec(commandObjects.tdigestMerge(mergeParams, destinationKey, sourceKey1, sourceKey2)); + assertThat(merge, equalTo("OK")); + + Double minAfterMerge = exec(commandObjects.tdigestMin(destinationKey)); + assertThat(minAfterMerge, equalTo(10.0)); + + Double maxAfterMerge = exec(commandObjects.tdigestMax(destinationKey)); + assertThat(maxAfterMerge, equalTo(40.0)); + } + + @Test + public void testTDigestReset() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 5.0, 10.0, 15.0)); + assertThat(add, equalTo("OK")); + + Double minBeforeReset = exec(commandObjects.tdigestMin(key)); + assertThat(minBeforeReset, equalTo(5.0)); + + Double maxBeforeReset = exec(commandObjects.tdigestMax(key)); + assertThat(maxBeforeReset, equalTo(15.0)); + + String reset = exec(commandObjects.tdigestReset(key)); + assertThat(reset, equalTo("OK")); + + Double minAfterReset = exec(commandObjects.tdigestMin(key)); + assertThat(minAfterReset, notANumber()); + + Double maxAfterReset = exec(commandObjects.tdigestMax(key)); + assertThat(maxAfterReset, notANumber()); + } + + @Test + public void testTDigestCdf() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0, 4.0, 5.0)); + assertThat(add, equalTo("OK")); + + List cdf = exec(commandObjects.tdigestCDF(key, 1.0, 3.0, 5.0)); + + assertThat(cdf, notNullValue()); + assertThat(cdf.size(), equalTo(3)); + assertThat(cdf.get(0), lessThanOrEqualTo(0.2)); + assertThat(cdf.get(1), lessThanOrEqualTo(0.6)); + assertThat(cdf.get(2), lessThanOrEqualTo(1.0)); + } + + @Test + public void testTDigestQuantile() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0, 4.0, 5.0)); + assertThat(add, equalTo("OK")); + + List quantile = exec(commandObjects.tdigestQuantile(key, 0.25, 0.5, 0.75)); + + assertThat(quantile, notNullValue()); + assertThat(quantile.size(), equalTo(3)); + assertThat(quantile.get(0), lessThanOrEqualTo(2.0)); + assertThat(quantile.get(1), lessThanOrEqualTo(3.0)); + assertThat(quantile.get(2), lessThanOrEqualTo(4.0)); + } + + @Test + public void testTDigestTrimmedMean() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0, 4.0, 5.0)); + assertThat(add, equalTo("OK")); + + Double trimmedMean = exec(commandObjects.tdigestTrimmedMean(key, 0.1, 0.9)); + + assertThat(trimmedMean, notNullValue()); + assertThat(trimmedMean, lessThanOrEqualTo(4.0)); + assertThat(trimmedMean, greaterThanOrEqualTo(2.0)); + } + + @Test + public void testTDigestRankAndRevRank() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0, 4.0, 5.0)); + assertThat(add, equalTo("OK")); + + List rank = exec(commandObjects.tdigestRank(key, 1.0, 3.0, 5.0)); + + assertThat(rank, notNullValue()); + assertThat(rank.size(), equalTo(3)); + assertThat(rank.get(0), lessThanOrEqualTo(1L)); + assertThat(rank.get(1), lessThanOrEqualTo(3L)); + assertThat(rank.get(2), lessThanOrEqualTo(5L)); + + List revRank = exec(commandObjects.tdigestRevRank(key, 1.0, 3.0, 5.0)); + + assertThat(revRank, notNullValue()); + assertThat(revRank.size(), equalTo(3)); + assertThat(revRank.get(0), greaterThanOrEqualTo(4L)); + assertThat(revRank.get(1), greaterThanOrEqualTo(2L)); + assertThat(revRank.get(2), greaterThanOrEqualTo(0L)); + } + + @Test + public void testTDigestByRankAndByRevRank() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 0.5, 1.5, 2.5, 3.5, 4.5)); + assertThat(add, equalTo("OK")); + + List byRank = exec(commandObjects.tdigestByRank(key, 0, 2, 4)); + + assertThat(byRank, notNullValue()); + assertThat(byRank.size(), equalTo(3)); + assertThat(byRank.get(0), closeTo(0.5, 0.1)); + assertThat(byRank.get(1), closeTo(2.5, 0.1)); + assertThat(byRank.get(2), closeTo(4.5, 0.1)); + + List byRevRank = exec(commandObjects.tdigestByRevRank(key, 0, 2, 4)); + + assertThat(byRevRank, notNullValue()); + assertThat(byRevRank.size(), equalTo(3)); + assertThat(byRevRank.get(0), closeTo(4.5, 0.1)); + assertThat(byRevRank.get(1), closeTo(2.5, 0.1)); + assertThat(byRevRank.get(2), closeTo(0.5, 0.1)); + } + + @Test + public void testTDigestInfo() { + String key = "testTDigest"; + + String create = exec(commandObjects.tdigestCreate(key)); + assertThat(create, equalTo("OK")); + + String add = exec(commandObjects.tdigestAdd(key, 1.0, 2.0, 3.0)); + assertThat(add, equalTo("OK")); + + Map info = exec(commandObjects.tdigestInfo(key)); + + assertThat(info, notNullValue()); + assertThat(info, hasKey("Compression")); + assertThat(info, hasEntry("Observations", 3L)); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java new file mode 100644 index 0000000000..5fde288839 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java @@ -0,0 +1,108 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import java.util.Collection; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import redis.clients.jedis.CommandObject; +import redis.clients.jedis.CommandObjects; +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.FlushMode; +import redis.clients.jedis.commands.CommandsTestsParameters; +import redis.clients.jedis.executors.CommandExecutor; +import redis.clients.jedis.executors.DefaultCommandExecutor; +import redis.clients.jedis.providers.ConnectionProvider; +import redis.clients.jedis.providers.PooledConnectionProvider; + +/** + * Base class for CommandObjects tests. The tests are parameterized to run with + * several versions of RESP. The idea is to test commands at this low level, using + * a simple executor. Higher level concepts like {@link redis.clients.jedis.UnifiedJedis}, + * or {@link redis.clients.jedis.PipeliningBase} can be tested separately with mocks. + *

+ * This class provides the basic setup, except the {@link HostAndPort} for connecting + * to a running Redis server. That one is provided by abstract subclasses, depending + * on if a Redis Stack server is needed, or a standalone suffices. + */ +@RunWith(Parameterized.class) +public abstract class CommandObjectsTestBase { + + /** + * Input data for parameterized tests. In principle all subclasses of this + * class should be parameterized tests, to run with several versions of RESP. + * + * @see CommandsTestsParameters#respVersions() + */ + @Parameterized.Parameters + public static Collection data() { + return CommandsTestsParameters.respVersions(); + } + + /** + * RESP protocol used in the tests. Injected from subclasses. + */ + protected final RedisProtocol protocol; + + /** + * Host and port of the Redis server to connect to. Injected from subclasses. + */ + protected final HostAndPort nodeInfo; + + /** + * Password to use when connecting to the Redis server, if needed. Injected from subclasses. + */ + private final String authPassword; + + /** + * The {@link CommandObjects} to use for the tests. This is the subject-under-test. + */ + protected final CommandObjects commandObjects; + + /** + * A {@link CommandExecutor} that can execute commands against the running Redis server. + * Not exposed to subclasses, which should use a convenience method instead. + */ + private CommandExecutor commandExecutor; + + public CommandObjectsTestBase(RedisProtocol protocol, HostAndPort nodeInfo, String authPassword) { + this.protocol = protocol; + this.nodeInfo = nodeInfo; + this.authPassword = authPassword; + commandObjects = new CommandObjects(); + commandObjects.setProtocol(protocol); + } + + @Before + public void setUp() { + // Configure a default command executor. + DefaultJedisClientConfig clientConfig = DefaultJedisClientConfig.builder() + .protocol(protocol).password(authPassword).build(); + + ConnectionProvider connectionProvider = new PooledConnectionProvider(nodeInfo, clientConfig); + + commandExecutor = new DefaultCommandExecutor(connectionProvider); + + // Cleanup before each test. + assertThat( + commandExecutor.executeCommand(commandObjects.flushAll()), + equalTo("OK")); + + assertThat( + commandExecutor.executeCommand(commandObjects.functionFlush(FlushMode.SYNC)), + equalTo("OK")); + } + + /** + * Convenience method for subclasses, for running any {@link CommandObject}. + */ + protected T exec(CommandObject commandObject) { + return commandExecutor.executeCommand(commandObject); + } + +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTimeSeriesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTimeSeriesCommandsTest.java new file mode 100644 index 0000000000..374ca315c2 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTimeSeriesCommandsTest.java @@ -0,0 +1,622 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.timeseries.AggregationType; +import redis.clients.jedis.timeseries.TSAlterParams; +import redis.clients.jedis.timeseries.TSCreateParams; +import redis.clients.jedis.timeseries.TSElement; +import redis.clients.jedis.timeseries.TSGetParams; +import redis.clients.jedis.timeseries.TSInfo; +import redis.clients.jedis.timeseries.TSMGetElement; +import redis.clients.jedis.timeseries.TSMGetParams; +import redis.clients.jedis.timeseries.TSMRangeElements; +import redis.clients.jedis.timeseries.TSMRangeParams; +import redis.clients.jedis.timeseries.TSRangeParams; + +/** + * Tests related to Time series commands. + */ +public class CommandObjectsTimeSeriesCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsTimeSeriesCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testTsAddAndRange() throws InterruptedException { + String key = "testTs"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + long currentTime = System.currentTimeMillis(); + double[] values = { 42.0, 43.0, 44.0 }; + for (double value : values) { + Long add = exec(commandObjects.tsAdd(key, value)); + assertThat(add, notNullValue()); + + // short delay to avoid the same timestamp + Thread.sleep(10); + } + + List range = exec(commandObjects.tsRange(key, currentTime - 1000, currentTime + 1000)); + + assertThat(range, hasSize(values.length)); + for (int i = 0; i < values.length; i++) { + assertThat(range.get(i).getValue(), equalTo(values[i])); + } + } + + @Test + public void testTsAddWithTimestampDelAndRangeWithPreDeleteAssert() { + String key = "testTs"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + long timestamp1 = 1000; + double value1 = 42.0; + + long timestamp2 = 2000; + double value2 = 43.0; + + Long add1 = exec(commandObjects.tsAdd(key, timestamp1, value1)); + assertThat(add1, notNullValue()); + + Long add2 = exec(commandObjects.tsAdd(key, timestamp2, value2)); + assertThat(add2, notNullValue()); + + List preDelRange = exec(commandObjects.tsRange(key, timestamp1 - 500, timestamp2 + 500)); + + assertThat(preDelRange, hasSize(2)); + assertThat(preDelRange.get(0).getValue(), equalTo(value1)); + assertThat(preDelRange.get(1).getValue(), equalTo(value2)); + + Long del = exec(commandObjects.tsDel(key, timestamp1 - 500, timestamp1 + 500)); + assertThat(del, equalTo(1L)); + + List postDelRange = exec(commandObjects.tsRange(key, timestamp1 - 500, timestamp2 + 500)); + + assertThat(postDelRange, hasSize(1)); + assertThat(postDelRange.get(0).getValue(), equalTo(value2)); + } + + @Test + public void testTsAddWithParams() { + String key = "testTs"; + + long timestamp = System.currentTimeMillis(); + double value = 42.0; + + TSCreateParams createParams = new TSCreateParams() + .uncompressed().retention(86400000); + + Long add = exec(commandObjects.tsAdd(key, timestamp, value, createParams)); + assertThat(add, notNullValue()); + + List range = exec(commandObjects.tsRange(key, timestamp - 1000, timestamp + 1000)); + + assertThat(range, hasSize(1)); + assertThat(range.get(0).getTimestamp(), equalTo(timestamp)); + assertThat(range.get(0).getValue(), equalTo(value)); + } + + @Test + public void testTsMAdd() { + String key1 = "testTsMAdd1"; + String key2 = "testTsMAdd2"; + + String create1 = exec(commandObjects.tsCreate(key1)); + assertThat(create1, equalTo("OK")); + + String create2 = exec(commandObjects.tsCreate(key2)); + assertThat(create2, equalTo("OK")); + + long timestamp1 = 2000; + long timestamp2 = 3000; + + Map.Entry entry1 = + new AbstractMap.SimpleEntry<>(key1, new TSElement(timestamp1, 42.0)); + + Map.Entry entry2 = + new AbstractMap.SimpleEntry<>(key2, new TSElement(timestamp2, 43.0)); + + List mAdd = exec(commandObjects.tsMAdd(entry1, entry2)); + assertThat(mAdd, contains(timestamp1, timestamp2)); + + List range1 = exec(commandObjects.tsRange(key1, timestamp1 - 1000, timestamp1 + 1000)); + + assertThat(range1, hasSize(1)); + assertThat(range1.get(0).getTimestamp(), equalTo(timestamp1)); + assertThat(range1.get(0).getValue(), equalTo(42.0)); + + List range2 = exec(commandObjects.tsRange(key2, timestamp2 - 1000, timestamp2 + 1000)); + + assertThat(range2, hasSize(1)); + assertThat(range2.get(0).getTimestamp(), equalTo(timestamp2)); + assertThat(range2.get(0).getValue(), equalTo(43.0)); + } + + @Test + public void testTsIncrByAndDecrBy() throws InterruptedException { + String key = "testTs"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + double initialValue = 10.0; + double incrementValue = 5.0; + double decrementValue = 3.0; + + Long initialAdd = exec(commandObjects.tsAdd(key, System.currentTimeMillis(), initialValue)); + assertThat(initialAdd, notNullValue()); + + Thread.sleep(50); + + Long incr = exec(commandObjects.tsIncrBy(key, incrementValue)); + assertThat(incr, notNullValue()); + + Thread.sleep(50); + + Long decr = exec(commandObjects.tsDecrBy(key, decrementValue)); + assertThat(decr, notNullValue()); + + TSElement latestElement = exec(commandObjects.tsGet(key)); + double expectedValue = initialValue + incrementValue - decrementValue; + assertThat(latestElement.getValue(), equalTo(expectedValue)); + + List range = exec(commandObjects.tsRange( + key, latestElement.getTimestamp() - 1000, latestElement.getTimestamp() + 1000)); + + assertThat(range.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(initialValue, 0.001), + closeTo(initialValue + incrementValue, 0.001), + closeTo(expectedValue, 0.001))); + } + + @Test + public void testTsIncrByAndDecrByWithTimestamp() { + String key = "testTs"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + double initialValue = 10.0; + double incrementValue = 5.0; + double decrementValue = 3.0; + + long initialTimestamp = System.currentTimeMillis(); + + Long initialAdd = exec(commandObjects.tsAdd(key, initialTimestamp, initialValue)); + assertThat(initialAdd, equalTo(initialTimestamp)); + + long incrementTimestamp = initialTimestamp + 1000; + + Long incr = exec(commandObjects.tsIncrBy(key, incrementValue, incrementTimestamp)); + assertThat(incr, equalTo(incrementTimestamp)); + + long decrementTimestamp = incrementTimestamp + 1000; + + Long decr = exec(commandObjects.tsDecrBy(key, decrementValue, decrementTimestamp)); + assertThat(decr, equalTo(decrementTimestamp)); + + List range = exec(commandObjects.tsRange( + key, initialTimestamp - 1000, decrementTimestamp + 1000)); + + assertThat(range.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(initialValue, 0.001), + closeTo(initialValue + incrementValue, 0.001), + closeTo(initialValue + incrementValue - decrementValue, 0.001))); + } + + @Test + public void testTsRange() { + String key = "tsKey"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + long fromTimestamp = 1000L; + long toTimestamp = 2000L; + + List initialRange = exec(commandObjects.tsRange(key, fromTimestamp - 100, toTimestamp + 100)); + assertThat(initialRange, hasSize(0)); + + exec(commandObjects.tsAdd(key, fromTimestamp, 1.0)); + exec(commandObjects.tsAdd(key, toTimestamp, 2.0)); + + List elementsByTimestamp = exec(commandObjects.tsRange(key, fromTimestamp - 100, toTimestamp + 100)); + + assertThat(elementsByTimestamp.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(1.0, 0.001), + closeTo(2.0, 0.001))); + + TSRangeParams rangeParams = new TSRangeParams(fromTimestamp - 100, toTimestamp + 100); + + List elementsByParams = exec(commandObjects.tsRange(key, rangeParams)); + + assertThat(elementsByParams.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(1.0, 0.001), + closeTo(2.0, 0.001))); + } + + @Test + public void testTsRevRange() { + String key = "tsRevKey"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + long fromTimestamp = 1000L; + long toTimestamp = 2000L; + + List initialRevRange = exec(commandObjects.tsRevRange(key, fromTimestamp - 100, toTimestamp + 100)); + assertThat(initialRevRange, hasSize(0)); + + exec(commandObjects.tsAdd(key, fromTimestamp, 1.0)); + exec(commandObjects.tsAdd(key, toTimestamp, 2.0)); + + List elementsByTimestamp = exec(commandObjects.tsRevRange(key, fromTimestamp - 100, toTimestamp + 100)); + + assertThat(elementsByTimestamp.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(2.0, 0.001), + closeTo(1.0, 0.001))); + + TSRangeParams rangeParams = new TSRangeParams(fromTimestamp - 100, toTimestamp + 100); + + List elementsByParams = exec(commandObjects.tsRevRange(key, rangeParams)); + + assertThat(elementsByParams.stream().map(TSElement::getValue).collect(Collectors.toList()), contains( + closeTo(2.0, 0.001), + closeTo(1.0, 0.001))); + } + + @Test + public void testTsMRangeCommands() { + String key1 = "tsMRangeKey1"; + String key2 = "tsMRangeKey2"; + + long fromTimestamp = 1000L; + long toTimestamp = 3000L; + + String filter = "sensor_id=1234"; + + Map initialMRange = exec(commandObjects.tsMRange( + fromTimestamp - 100, toTimestamp + 100, filter)); + assertThat(initialMRange.entrySet(), hasSize(0)); + + TSCreateParams createParams = new TSCreateParams() + .uncompressed().label("sensor_id", "1234"); + + exec(commandObjects.tsAdd(key1, fromTimestamp, 1.0, createParams)); + exec(commandObjects.tsAdd(key1, fromTimestamp + 500, 1.5, createParams)); + exec(commandObjects.tsAdd(key2, toTimestamp - 500, 2.5, createParams)); + exec(commandObjects.tsAdd(key2, toTimestamp, 2.0, createParams)); + + Map range = exec(commandObjects.tsMRange( + fromTimestamp - 100, toTimestamp + 100, filter)); + + assertThat(range.keySet(), hasItems(key1, key2)); + assertThat(range.get(key1).getElements().stream().map(TSElement::getValue).collect(Collectors.toList()), + containsInAnyOrder(closeTo(1.0, 0.001), closeTo(1.5, 0.001))); + assertThat(range.get(key2).getElements().stream().map(TSElement::getValue).collect(Collectors.toList()), + containsInAnyOrder(closeTo(2.5, 0.001), closeTo(2.0, 0.001))); + + Map revRangeResult = exec(commandObjects.tsMRevRange( + fromTimestamp - 100, toTimestamp + 100, filter)); + + assertThat(revRangeResult.keySet(), hasItems(key1, key2)); + assertThat(revRangeResult.get(key1).getElements().stream().map(TSElement::getValue).collect(Collectors.toList()), + containsInAnyOrder(closeTo(1.5, 0.001), closeTo(1.0, 0.001))); + assertThat(revRangeResult.get(key2).getElements().stream().map(TSElement::getValue).collect(Collectors.toList()), + containsInAnyOrder(closeTo(2.0, 0.001), closeTo(2.5, 0.001))); + + TSMRangeParams multiRangeParamsA = + new TSMRangeParams(fromTimestamp - 100, toTimestamp + 100).filter(filter); + + Map rangeResultWithParams = exec(commandObjects.tsMRange(multiRangeParamsA)); + + assertThat(rangeResultWithParams.keySet(), hasItems(key1, key2)); + assertThat(rangeResultWithParams, equalTo(range)); + + TSMRangeParams multiRangeParams = new TSMRangeParams(fromTimestamp - 100, toTimestamp + 100).filter(filter); + + Map revRangeResultWithParams = exec(commandObjects.tsMRevRange(multiRangeParams)); + + assertThat(revRangeResultWithParams.keySet(), hasItems(key1, key2)); + assertThat(revRangeResultWithParams, equalTo(revRangeResult)); + } + + @Test + public void testTsGet() { + String key = "tsGetKey"; + + String create = exec(commandObjects.tsCreate(key)); + assertThat(create, equalTo("OK")); + + long timestamp = 1000L; + + double firstValue = 2.5; + double secondValue = 3.5; + + TSElement initialGet = exec(commandObjects.tsGet(key)); + assertThat(initialGet, nullValue()); + + exec(commandObjects.tsAdd(key, timestamp, firstValue)); + exec(commandObjects.tsAdd(key, timestamp + 100, secondValue)); + + TSElement getLastValue = exec(commandObjects.tsGet(key)); + assertThat(getLastValue, notNullValue()); + assertThat(getLastValue.getValue(), closeTo(secondValue, 0.001)); + + TSElement getWithParams = exec(commandObjects.tsGet(key, new TSGetParams().latest())); + assertThat(getWithParams, notNullValue()); + assertThat(getWithParams.getValue(), closeTo(secondValue, 0.001)); + } + + @Test + public void testTsMGet() { + String key1 = "tsMGetKey1"; + String key2 = "tsMGetKey2"; + + long timestamp1 = 1000L; + long timestamp2 = 2000L; + + double value1 = 1.0; + double value2 = 2.0; + + String filter = "sensor_id=1234"; + + TSCreateParams createParams = new TSCreateParams() + .uncompressed().label("sensor_id", "1234"); + + exec(commandObjects.tsAdd(key1, timestamp1, value1, createParams)); + exec(commandObjects.tsAdd(key2, timestamp2, value2, createParams)); + + TSMGetParams multiGetParams = new TSMGetParams().withLabels(); + + Map elements = exec(commandObjects.tsMGet(multiGetParams, filter)); + + assertThat(elements.keySet(), hasItems(key1, key2)); + + TSMGetElement element1 = elements.get(key1); + assertThat(element1, notNullValue()); + assertThat(element1.getElement().getTimestamp(), equalTo(timestamp1)); + assertThat(element1.getElement().getValue(), closeTo(value1, 0.001)); + + TSMGetElement element2 = elements.get(key2); + assertThat(element2, notNullValue()); + assertThat(element2.getElement().getTimestamp(), equalTo(timestamp2)); + assertThat(element2.getElement().getValue(), closeTo(value2, 0.001)); + + assertThat(element1.getLabels(), hasEntry("sensor_id", "1234")); + assertThat(element2.getLabels(), hasEntry("sensor_id", "1234")); + } + + @Test + public void testTsCreateRule() { + String sourceKey = "tsSourceKey"; + String destKey = "tsDestKey"; + + AggregationType aggregationType = AggregationType.AVG; + + long timeBucket = 60000; // 1 minute + + exec(commandObjects.tsCreate(sourceKey)); + exec(commandObjects.tsCreate(destKey)); + + String createRule = exec(commandObjects.tsCreateRule(sourceKey, destKey, aggregationType, timeBucket)); + assertThat(createRule, equalTo("OK")); + + long timestamp1 = 1000L; // 1 second + double value1 = 10.0; + exec(commandObjects.tsAdd(sourceKey, timestamp1, value1)); + + long timestamp2 = 30000L; // 30 seconds + double value2 = 20.0; + exec(commandObjects.tsAdd(sourceKey, timestamp2, value2)); + + long timestamp3 = 100000L; // 100 seconds, should be in the second aggregation bucket + double value3 = 30.0; + exec(commandObjects.tsAdd(sourceKey, timestamp3, value3)); + + long timestamp4 = 200000L; // 200 seconds, should be in the fourth aggregation bucket + double value4 = 1.0; + exec(commandObjects.tsAdd(sourceKey, timestamp4, value4)); + + // Verify that aggregated data appears in the destination key + // We only check the first three buckets, i.e. 180 seconds + // The average of value1 and value2 should be in the first bucket, value3 in the second + List destElements = exec(commandObjects.tsRange(destKey, 0, 180000)); + + assertThat(destElements.size(), equalTo(2)); + + double expectedAvgFirstBucket = (value1 + value2) / 2.0; + assertThat(destElements.get(0).getValue(), closeTo(expectedAvgFirstBucket, 0.001)); + + assertThat(destElements.get(1).getValue(), closeTo(value3, 0.001)); + } + + @Test + public void testTsCreateRuleWithAlign() { + String sourceKey = "tsSourceKey"; + String destKey = "tsDestKey"; + + AggregationType aggregationType = AggregationType.AVG; + + long timeBucket = 60000; // 1 minute + + exec(commandObjects.tsCreate(sourceKey)); + exec(commandObjects.tsCreate(destKey)); + + String createRule = exec(commandObjects.tsCreateRule(sourceKey, destKey, aggregationType, timeBucket, 2000)); + assertThat(createRule, equalTo("OK")); + + long timestamp1 = 1000L; // 1 second + double value1 = 10.0; + exec(commandObjects.tsAdd(sourceKey, timestamp1, value1)); + + long timestamp2 = 30000L; // 30 seconds + double value2 = 20.0; + exec(commandObjects.tsAdd(sourceKey, timestamp2, value2)); + + long timestamp3 = 100000L; // 100 seconds, should be in the second aggregation bucket + double value3 = 30.0; + exec(commandObjects.tsAdd(sourceKey, timestamp3, value3)); + + long timestamp4 = 200000L; // 200 seconds, should be in the fourth aggregation bucket + double value4 = 1.0; + exec(commandObjects.tsAdd(sourceKey, timestamp4, value4)); + + // Verify that aggregated data appears in the destination key + // We only check the first three buckets, i.e. 180 seconds + // The average of value1 and value2 should be in the first bucket, value3 in the second + List destElements = exec(commandObjects.tsRange(destKey, 2000, 182000)); + + assertThat(destElements.size(), equalTo(2)); + assertThat(destElements.get(0).getValue(), closeTo(value2, 0.001)); + assertThat(destElements.get(1).getValue(), closeTo(value3, 0.001)); + } + + + @Test + public void testTsDeleteRule() { + String sourceKey = "tsSourceKeyForDeletionWithData"; + String destKey = "tsDestKeyForDeletionWithData"; + + AggregationType aggregationType = AggregationType.SUM; + + long bucketDuration = 60000; // 1 minute + + exec(commandObjects.tsCreate(sourceKey)); + exec(commandObjects.tsCreate(destKey)); + + exec(commandObjects.tsCreateRule(sourceKey, destKey, aggregationType, bucketDuration)); + + long initialTimestamp = 1000; + exec(commandObjects.tsAdd(sourceKey, initialTimestamp, 10.0)); + + // This will force aggregation of the first bucket + exec(commandObjects.tsAdd(sourceKey, initialTimestamp + bucketDuration, 20.0)); + + List initialAggregatedData = exec(commandObjects.tsRange(destKey, 0, bucketDuration)); + + assertThat(initialAggregatedData.stream().map(TSElement::getValue).collect(Collectors.toList()), + contains(closeTo(10.0, 0.001))); + + List initialAggregatedDataSecondBucket = exec(commandObjects.tsRange(destKey, bucketDuration, 2 * bucketDuration)); + + assertThat(initialAggregatedDataSecondBucket.stream().map(TSElement::getValue).collect(Collectors.toList()), + empty()); + + // Delete the rule + String deleteRule = exec(commandObjects.tsDeleteRule(sourceKey, destKey)); + assertThat(deleteRule, equalTo("OK")); + + // Add more data to the source key after the rule has been deleted + long postDeletionTimestamp = initialTimestamp + bucketDuration + 10; + + exec(commandObjects.tsAdd(sourceKey, postDeletionTimestamp, 20)); + + // This should force the aggregation of the second bucket, if there was a rule + exec(commandObjects.tsAdd(sourceKey, postDeletionTimestamp + bucketDuration, 20)); + + // Make sure that the data in the destination key has not changed + List postDeletionAggregatedData = exec(commandObjects.tsRange(destKey, 0, bucketDuration)); + + assertThat(postDeletionAggregatedData.stream().map(TSElement::getValue).collect(Collectors.toList()), + contains(closeTo(10.0, 0.001))); + + List postDeletionAggregatedDataSecondBucket = exec(commandObjects.tsRange(destKey, bucketDuration, 2 * bucketDuration)); + + assertThat(postDeletionAggregatedDataSecondBucket.stream().map(TSElement::getValue).collect(Collectors.toList()), + empty()); + } + + @Test + public void testTsQueryIndexWithKeyCreation() { + String key1 = "temperature:sensor:1"; + String key2 = "temperature:sensor:2"; + String key3 = "humidity:sensor:1"; + + TSCreateParams paramsTempSensor1 = new TSCreateParams() + .label("type", "temperature").label("sensor_id", "1"); + + exec(commandObjects.tsCreate(key1, paramsTempSensor1)); + + TSCreateParams paramsTempSensor2 = new TSCreateParams() + .label("type", "temperature").label("sensor_id", "2"); + + exec(commandObjects.tsCreate(key2, paramsTempSensor2)); + + TSCreateParams paramsHumiditySensor1 = new TSCreateParams() + .label("type", "humidity").label("sensor_id", "1"); + + exec(commandObjects.tsCreate(key3, paramsHumiditySensor1)); + + String[] filters = new String[]{ "type=temperature" }; + List matchingKeys = exec(commandObjects.tsQueryIndex(filters)); + + assertThat(matchingKeys, containsInAnyOrder(key1, key2)); + } + + @Test + public void testTsAlterAndInfo() { + String key = "tsKey"; + + TSCreateParams createParams = new TSCreateParams() + .label("sensor", "temperature"); + + TSAlterParams alterParams = new TSAlterParams() + .label("sensor", "humidity"); + + String create = exec(commandObjects.tsCreate(key, createParams)); + assertThat(create, equalTo("OK")); + + TSInfo info = exec(commandObjects.tsInfo(key)); + + assertThat(info, notNullValue()); + assertThat(info.getLabels().get("sensor"), equalTo("temperature")); + assertThat(info.getChunks(), nullValue()); + + TSInfo debugInfo = exec(commandObjects.tsInfoDebug(key)); + + assertThat(debugInfo, notNullValue()); + assertThat(debugInfo.getLabels().get("sensor"), equalTo("temperature")); + assertThat(debugInfo.getChunks(), notNullValue()); + + String alter = exec(commandObjects.tsAlter(key, alterParams)); + + assertThat(alter, equalTo("OK")); + + TSInfo infoAfter = exec(commandObjects.tsInfo(key)); + + assertThat(infoAfter, notNullValue()); + assertThat(infoAfter.getLabels().get("sensor"), equalTo("humidity")); + assertThat(infoAfter.getChunks(), nullValue()); + + TSInfo debugInfoAfter = exec(commandObjects.tsInfoDebug(key)); + + assertThat(debugInfoAfter, notNullValue()); + assertThat(debugInfoAfter.getLabels().get("sensor"), equalTo("humidity")); + assertThat(debugInfoAfter.getChunks(), notNullValue()); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTopkCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTopkCommandsTest.java new file mode 100644 index 0000000000..4091fd5280 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTopkCommandsTest.java @@ -0,0 +1,118 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; + +/** + * Tests related to Top-k commands. + */ +public class CommandObjectsTopkCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsTopkCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testTopKAddAndQuery() { + String key = "testTopK"; + + long topKSize = 3; + + String reserve = exec(commandObjects.topkReserve(key, topKSize)); + assertThat(reserve, equalTo("OK")); + + List add = exec(commandObjects.topkAdd(key, + "apple", "banana", "carrot", "apple", "banana", + "date", "eggplant", "fig", "grape", "apple")); + // As the values are added, some items get kicked out from top 3. They are returned in the response. + assertThat(add, contains( + nullValue(), nullValue(), nullValue(), nullValue(), nullValue(), + equalTo("carrot"), equalTo("date"), equalTo("eggplant"), equalTo("fig"), nullValue() + )); + + List query = exec(commandObjects.topkQuery(key, "apple", "banana", "carrot", "grape")); + assertThat(query, contains(true, true, false, true)); + } + + @Test + public void testTopKIncrBy() { + String key = "testTopK"; + + long topKSize = 3; + + Map itemIncrements = new HashMap<>(); + itemIncrements.put("apple", 2L); + itemIncrements.put("banana", 3L); + itemIncrements.put("carrot", 1L); + itemIncrements.put("date", 5L); + + String reserve = exec(commandObjects.topkReserve(key, topKSize, 2000, 7, 0.9)); + assertThat(reserve, equalTo("OK")); + + List incrBy = exec(commandObjects.topkIncrBy(key, itemIncrements)); + // Due to Map's unpredictable order, we can't assert ordering of the result + assertThat(incrBy, hasSize(4)); + + List query = exec(commandObjects.topkQuery(key, "apple", "banana", "date", "carrot")); + assertThat(query, contains(true, true, true, false)); + } + + @Test + public void testTopKListAndListWithCount() { + String key = "testTopK"; + + long topKSize = 3; + + String reserve = exec(commandObjects.topkReserve(key, topKSize)); + assertThat(reserve, equalTo("OK")); + + List add = exec(commandObjects.topkAdd(key, + "apple", "banana", "carrot", "apple", "banana", + "date", "eggplant", "fig", "grape", "apple")); + assertThat(add, notNullValue()); + + List list = exec(commandObjects.topkList(key)); + assertThat(list, contains("apple", "banana", "grape")); + + Map listWithCount = exec(commandObjects.topkListWithCount(key)); + assertThat(listWithCount, aMapWithSize(3)); + assertThat(listWithCount, hasEntry("apple", 3L)); + assertThat(listWithCount, hasEntry("banana", 2L)); + assertThat(listWithCount, hasEntry("grape", 1L)); + } + + @Test + public void testTopKInfo() { + String key = "testTopK"; + + long topKSize = 3; + long width = 1000; + long depth = 7; + double decay = 0.9; + + String reserve = exec(commandObjects.topkReserve(key, topKSize, width, depth, decay)); + assertThat(reserve, equalTo("OK")); + + Map info = exec(commandObjects.topkInfo(key)); + + assertThat(info, notNullValue()); + assertThat(info, hasEntry("k", 3L)); + assertThat(info, hasEntry("width", width)); + assertThat(info, hasEntry("depth", depth)); + assertThat(info, hasKey("decay")); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java new file mode 100644 index 0000000000..31528e8092 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTriggersAndFunctionsCommandsTest.java @@ -0,0 +1,66 @@ +package redis.clients.jedis.commands.commandobjects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.gears.TFunctionListParams; +import redis.clients.jedis.gears.TFunctionLoadParams; +import redis.clients.jedis.gears.resps.GearsLibraryInfo; + +/** + * Tests related to Triggers and functions commands. + */ +public class CommandObjectsTriggersAndFunctionsCommandsTest extends CommandObjectsModulesTestBase { + + public CommandObjectsTriggersAndFunctionsCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testTFunctionLoadAndCall() { + String libraryCode = "#!js api_version=1.0 name=lib\n" + + "redis.registerFunction('hello', ()=>{return 42;})"; + + TFunctionLoadParams params = new TFunctionLoadParams().replace(); + + String load = exec(commandObjects.tFunctionLoad(libraryCode, params)); + assertThat(load, equalTo("OK")); + + Object call = exec(commandObjects.tFunctionCall("lib", "hello", new ArrayList<>(), new ArrayList<>())); + assertThat(call.toString(), equalTo("42")); + + Object callAsync = exec(commandObjects.tFunctionCallAsync("lib", "hello", new ArrayList<>(), new ArrayList<>())); + assertThat(callAsync.toString(), equalTo("42")); + } + + @Test + public void testTFunctionDeleteAndList() { + String libraryCode = "#!js api_version=1.0 name=lib\n" + + "redis.registerFunction('hello', ()=>{return 42;})"; + + String load = exec(commandObjects.tFunctionLoad(libraryCode, new TFunctionLoadParams().replace())); + assertThat(load, equalTo("OK")); + + TFunctionListParams params = new TFunctionListParams().library("lib"); + + List list = exec(commandObjects.tFunctionList(params)); + + assertThat(list, hasSize(1)); + assertThat(list.get(0).getName(), equalTo("lib")); + assertThat(list.get(0).getFunctions(), hasSize(1)); + assertThat(list.get(0).getFunctions().get(0).getName(), equalTo("hello")); + + String delete = exec(commandObjects.tFunctionDelete("lib")); + assertThat(delete, equalTo("OK")); + + list = exec(commandObjects.tFunctionList(params)); + assertThat(list, empty()); + } +} diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/Person.java b/src/test/java/redis/clients/jedis/commands/commandobjects/Person.java new file mode 100644 index 0000000000..f5ff033401 --- /dev/null +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/Person.java @@ -0,0 +1,49 @@ +package redis.clients.jedis.commands.commandobjects; + +import java.util.Objects; + +/** + * Bean class used for testing Redis JSON commands. + */ +public class Person { + + private String name; + private int age; + + public Person() { + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } +}