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); + } +}