From 94805375b208978dea82e406b2efd7e179c03242 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 8 Apr 2024 11:58:00 +0300 Subject: [PATCH 1/2] Add more tests for the CommandObjects class Continue the series of tests dedicated to the CommandObjects class, mostly with generic commands and search, and with a bit of polishing the existing tests. --- .../CommandObjectsGenericCommandsTest.java | 1359 ++++++++++++++++- ...mandObjectsSearchAndQueryCommandsTest.java | 329 ++++ .../CommandObjectsSortedSetCommandsTest.java | 56 +- .../CommandObjectsStreamCommandsTest.java | 90 +- 4 files changed, 1811 insertions(+), 23 deletions(-) diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java index 0182de207f..1849d26687 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java @@ -1,23 +1,1034 @@ 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.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.args.ExpiryOption; +import redis.clients.jedis.params.RestoreParams; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.params.SortingParams; +import redis.clients.jedis.resps.ScanResult; + +/** + * Tests related to Generic commands. + */ +public class CommandObjectsGenericCommandsTest extends CommandObjectsStandaloneTestBase { + + public CommandObjectsGenericCommandsTest(RedisProtocol protocol) { + super(protocol); + } + + @Test + public void testExists() { + String key1 = "existsKey1"; + String key2 = "existsKey2"; + String value = "value"; + + exec(commandObjects.set(key1, value)); + exec(commandObjects.set(key2, value)); + + Boolean existsSingle = exec(commandObjects.exists(key1)); + assertThat(existsSingle, equalTo(true)); + + Long existsMultiple = exec(commandObjects.exists(key1, key2, "nonExistingKey")); + assertThat(existsMultiple, equalTo(2L)); + + Boolean existsSingleByte = exec(commandObjects.exists(key1.getBytes())); + assertThat(existsSingleByte, equalTo(true)); + + Long existsMultipleByte = exec(commandObjects.exists(key1.getBytes(), key2.getBytes(), "nonExistingKey".getBytes())); + assertThat(existsMultipleByte, equalTo(2L)); + + Boolean existsNonExisting = exec(commandObjects.exists("nonExistingKey")); + assertThat(existsNonExisting, equalTo(false)); + + Boolean existsNonExistingBytes = exec(commandObjects.exists("nonExistingKey".getBytes())); + assertThat(existsNonExistingBytes, equalTo(false)); + } + + @Test + public void testPersist() { + String key1 = "persistKey1"; + byte[] key2 = "persistKey2".getBytes(); + String value = "value"; + int expireTime = 10; // seconds + + exec(commandObjects.setex(key1, expireTime, value)); + exec(commandObjects.setex(key2, expireTime, value.getBytes())); + + Long ttlBeforePersist1 = exec(commandObjects.ttl(key1)); + assertThat(ttlBeforePersist1, greaterThan(0L)); + + Long ttlBeforePersist2 = exec(commandObjects.ttl(key2)); + assertThat(ttlBeforePersist2, greaterThan(0L)); + + Long persist1 = exec(commandObjects.persist(key1)); + assertThat(persist1, equalTo(1L)); + + Long persist2 = exec(commandObjects.persist(key2)); + assertThat(persist2, equalTo(1L)); + + Long ttlAfterPersist1 = exec(commandObjects.ttl(key1)); + assertThat(ttlAfterPersist1, equalTo(-1L)); + + Long ttlAfterPersist2 = exec(commandObjects.ttl(key2)); + assertThat(ttlAfterPersist2, equalTo(-1L)); + } + + @Test + public void testType() { + String stringKey = "stringKey"; + String listKey = "listKey"; + byte[] hashKey = "hashKey".getBytes(); + + exec(commandObjects.set(stringKey, "value")); + exec(commandObjects.rpush(listKey, "value")); + exec(commandObjects.hset(hashKey, "field".getBytes(), "hvalue".getBytes())); + + String stringKeyType = exec(commandObjects.type(stringKey)); + assertThat(stringKeyType, equalTo("string")); + + String listKeyType = exec(commandObjects.type(listKey)); + assertThat(listKeyType, equalTo("list")); + + String hashKeyType = exec(commandObjects.type(hashKey)); + assertThat(hashKeyType, equalTo("hash")); + + String nonExistingKeyType = exec(commandObjects.type("nonExistingKey")); + assertThat(nonExistingKeyType, equalTo("none")); + } + + @Test + public void testDumpAndRestore() { + String key = "dumpRestoreKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + byte[] dumpedValue = exec(commandObjects.dump(key)); + assertThat(dumpedValue, notNullValue()); + + exec(commandObjects.del(key)); + + Boolean existsAfterDel = exec(commandObjects.exists(key)); + assertThat(existsAfterDel, equalTo(false)); + + String restore = exec(commandObjects.restore(key, 0, dumpedValue)); + assertThat(restore, equalTo("OK")); + + String restoredValue = exec(commandObjects.get(key)); + assertThat(restoredValue, equalTo(value)); + + Long ttlAfterRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterRestore, equalTo(-1L)); + + exec(commandObjects.del(key)); + + Boolean existsAfterSecondDel = exec(commandObjects.exists(key)); + assertThat(existsAfterSecondDel, equalTo(false)); + + long ttl = 5000; // milliseconds + RestoreParams params = new RestoreParams().idleTime(500); + + String restoreWithParams = exec(commandObjects.restore(key, ttl, dumpedValue, params)); + assertThat(restoreWithParams, equalTo("OK")); + + String secondRestoredValue = exec(commandObjects.get(key)); + assertThat(secondRestoredValue, equalTo(value)); + + Long ttlAfterSecondRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterSecondRestore, greaterThan(0L)); + } + + @Test + public void testDumpAndRestoreBinary() { + byte[] key = "dumpRestoreKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + byte[] dumpedValue = exec(commandObjects.dump(key)); + assertThat(dumpedValue, notNullValue()); + + exec(commandObjects.del(key)); + + Boolean existsAfterDel = exec(commandObjects.exists(key)); + assertThat(existsAfterDel, equalTo(false)); + + String restore = exec(commandObjects.restore(key, 0, dumpedValue)); + assertThat(restore, equalTo("OK")); + + byte[] restoredValue = exec(commandObjects.get(key)); + assertThat(restoredValue, equalTo(value)); + + Long ttlAfterRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterRestore, equalTo(-1L)); + + exec(commandObjects.del(key)); + + Boolean existsAfterSecondDel = exec(commandObjects.exists(key)); + assertThat(existsAfterSecondDel, equalTo(false)); + + long ttl = 5000; // milliseconds + RestoreParams params = new RestoreParams().idleTime(500); + + String restoreWithParams = exec(commandObjects.restore(key, ttl, dumpedValue, params)); + assertThat(restoreWithParams, equalTo("OK")); + + byte[] secondRestoredValue = exec(commandObjects.get(key)); + assertThat(secondRestoredValue, equalTo(value)); + + Long ttlAfterSecondRestore = exec(commandObjects.pttl(key)); + assertThat(ttlAfterSecondRestore, greaterThan(0L)); + } + + @Test + public void testExpireAndExpireTime() { + String key = "expireKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 60; + + Long expire = exec(commandObjects.expire(key, seconds)); + assertThat(expire, equalTo(1L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireAndExpireTimeBinary() { + byte[] key = "expireKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 60; + + Long expire = exec(commandObjects.expire(key, seconds)); + assertThat(expire, equalTo(1L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireWithExpiryOption() { + String key = "expireWithOptionKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 120; + ExpiryOption expiryOptionNX = ExpiryOption.NX; + + Long expireNx = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNx, equalTo(1L)); + + Long expireNxAgain = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNxAgain, equalTo(0L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testExpireWithExpiryOptionTimeBinary() { + byte[] key = "expireWithOptionKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + Long expireTimeBefore = exec(commandObjects.expireTime(key)); + assertThat(expireTimeBefore, equalTo(-1L)); + + long seconds = 120; + ExpiryOption expiryOptionNX = ExpiryOption.NX; + + Long expireNx = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNx, equalTo(1L)); + + Long expireNxAgain = exec(commandObjects.expire(key, seconds, expiryOptionNX)); + assertThat(expireNxAgain, equalTo(0L)); + + Long expireTimeAfter = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfter, greaterThan(System.currentTimeMillis() / 1000)); + } + + @Test + public void testPexpireAndPexpireTime() { + String key = "pexpireKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 15000; // 15 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfter = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfter, greaterThan(System.currentTimeMillis())); + } + + @Test + public void testPexpireAndPexpireTimeBinary() { + byte[] key = "pexpireKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 15000; // 15 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfter = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfter, greaterThan(System.currentTimeMillis())); + } + + @Test + public void testPexpireWithOptionsAndPexpireTime() { + String key = "pexpireWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 20000; // 20 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfterSet = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterSet, greaterThan(System.currentTimeMillis())); + + Long pexpireWithNx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpireWithNx, equalTo(0L)); + + Long pexpireWithXx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.XX)); + assertThat(pexpireWithXx, equalTo(1L)); + } + + @Test + public void testPexpireWithOptionsAndPexpireTimeBinary() { + byte[] key = "pexpireWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long expireTimeMillis = 20000; // 20 seconds + + Long pexpireTimeBefore = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeBefore, equalTo(-1L)); + + Long pexpire = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpire, equalTo(1L)); + + Long pexpireTimeAfterSet = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterSet, greaterThan(System.currentTimeMillis())); + + Long pexpireWithNx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.NX)); + assertThat(pexpireWithNx, equalTo(0L)); + + Long pexpireWithXx = exec(commandObjects.pexpire(key, expireTimeMillis, ExpiryOption.XX)); + assertThat(pexpireWithXx, equalTo(1L)); + } + + @Test + public void testExpireAtAndExpireTime() { + String key = "expireAtKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 10; // 10 seconds from now + + // Setting expire at in the future + Long expireAt = exec(commandObjects.expireAt(key, futureExpireTime)); + assertThat(expireAt, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(futureExpireTime)); + + // Setting expire at in the past should delete the key + long pastExpireTime = System.currentTimeMillis() / 1000 - 10; + Long expireAtPast = exec(commandObjects.expireAt(key, pastExpireTime)); + assertThat(expireAtPast, equalTo(1L)); + + Long expireTimeAfterPast = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testExpireAtAndExpireTimeBinary() { + byte[] key = "expireAtKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 10; // 10 seconds from now + + // Setting expire at in the future + Long expireAt = exec(commandObjects.expireAt(key, futureExpireTime)); + assertThat(expireAt, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(futureExpireTime)); + + // Setting expire at in the past should delete the key + long pastExpireTime = System.currentTimeMillis() / 1000 - 10; + Long expireAtPast = exec(commandObjects.expireAt(key, pastExpireTime)); + assertThat(expireAtPast, equalTo(1L)); + + Long expireTimeAfterPast = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testExpireAtWithOptionsAndExpireTime() { + String key = "expireAtWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 20; // 20 seconds from now + + // Setting expire at in the future, with NX + Long expireAtNx = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNx, equalTo(1L)); + + Long expireTimeAfterNx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNx, equalTo(futureExpireTime)); + + // Update expire at in the future, with XX + long laterFutureExpireTime = futureExpireTime + 10; + Long expireAtXx = exec(commandObjects.expireAt(key, laterFutureExpireTime, ExpiryOption.XX)); + assertThat(expireAtXx, equalTo(1L)); + + Long expireTimeAfterXx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterXx, equalTo(laterFutureExpireTime)); + + // Try to reset with NX, should fail + Long expireAtNxAgain = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNxAgain, equalTo(0L)); + + Long expireTimeAfterNxAgain = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNxAgain, equalTo(laterFutureExpireTime)); + } + + @Test + public void testExpireAtWithOptionsAndExpireTimeBinary() { + byte[] key = "expireAtWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureExpireTime = System.currentTimeMillis() / 1000 + 20; // 20 seconds from now + + // Setting expire at in the future, with NX + Long expireAtNx = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNx, equalTo(1L)); + + Long expireTimeAfterNx = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNx, equalTo(futureExpireTime)); + + // Update expire at in the future, with XX + long laterFutureExpireTime = futureExpireTime + 10; + Long expireAtXx = exec(commandObjects.expireAt(key, laterFutureExpireTime, ExpiryOption.XX)); + assertThat(expireAtXx, equalTo(1L)); + + Long expireTime = exec(commandObjects.expireTime(key)); + assertThat(expireTime, equalTo(laterFutureExpireTime)); + + // Try to reset with NX, should fail + Long expireAtNxAgain = exec(commandObjects.expireAt(key, futureExpireTime, ExpiryOption.NX)); + assertThat(expireAtNxAgain, equalTo(0L)); + + Long expireTimeAfterNxAgain = exec(commandObjects.expireTime(key)); + assertThat(expireTimeAfterNxAgain, equalTo(laterFutureExpireTime)); + } + + @Test + public void testPexpireAtAndPexpireTime() { + String key = "pexpireAtKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 20000; // 20 seconds from now + + Long pexpireAt = exec(commandObjects.pexpireAt(key, futureTimestampMillis)); + assertThat(pexpireAt, equalTo(1L)); + + Long pexpireTime = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTime, equalTo(futureTimestampMillis)); + + // Setting pexpire at a past timestamp should delete the key + long pastTimestampMillis = System.currentTimeMillis() - 20000; + Long pexpireAtPast = exec(commandObjects.pexpireAt(key, pastTimestampMillis)); + assertThat(pexpireAtPast, equalTo(1L)); + + Long pexpireTimeAfterPast = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testPexpireAtAndPexpireTimeBinary() { + byte[] key = "pexpireAtKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 20000; // 20 seconds from now + + Long pexpireAt = exec(commandObjects.pexpireAt(key, futureTimestampMillis)); + assertThat(pexpireAt, equalTo(1L)); + + Long pexpireTime = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTime, equalTo(futureTimestampMillis)); + + // Setting pexpire at a past timestamp should delete the key + long pastTimestampMillis = System.currentTimeMillis() - 20000; + Long pexpireAtPast = exec(commandObjects.pexpireAt(key, pastTimestampMillis)); + assertThat(pexpireAtPast, equalTo(1L)); + + Long pexpireTimeAfterPast = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterPast, equalTo(-2L)); // Key does not exist + } + + @Test + public void testPexpireAtWithOptionsAndPexpireTime() { + String key = "pexpireAtWithOptionsKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 30000; // 30 seconds from now + + // Setting with NX + Long pexpireAtNx = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNx, equalTo(1L)); + + Long pexpireTimeAfterNx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNx, equalTo(futureTimestampMillis)); + + // Updating with XX + long laterFutureTimestampMillis = futureTimestampMillis + 10000; // Further 10 seconds in the future + Long pexpireAtXx = exec(commandObjects.pexpireAt(key, laterFutureTimestampMillis, ExpiryOption.XX)); + assertThat(pexpireAtXx, equalTo(1L)); + + Long pexpireTimeAfterXx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterXx, equalTo(laterFutureTimestampMillis)); + + // Updating with NX fails + Long pexpireAtNxAgain = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNxAgain, equalTo(0L)); + + Long pexpireTimeAfterNxAgain = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNxAgain, equalTo(laterFutureTimestampMillis)); + } + + @Test + public void testPexpireAtWithOptionsAndPexpireTimeBinary() { + byte[] key = "pexpireAtWithOptionsKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + long futureTimestampMillis = System.currentTimeMillis() + 30000; // 30 seconds from now + + // Setting with NX + Long pexpireAtNx = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNx, equalTo(1L)); + + Long pexpireTimeAfterNx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNx, equalTo(futureTimestampMillis)); + + // Updating with XX + long laterFutureTimestampMillis = futureTimestampMillis + 10000; // Further 10 seconds in the future + Long pexpireAtXx = exec(commandObjects.pexpireAt(key, laterFutureTimestampMillis, ExpiryOption.XX)); + assertThat(pexpireAtXx, equalTo(1L)); + + Long pexpireTimeAfterXx = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterXx, equalTo(laterFutureTimestampMillis)); + + // Updating with NX fails + Long pexpireAtNxAgain = exec(commandObjects.pexpireAt(key, futureTimestampMillis, ExpiryOption.NX)); + assertThat(pexpireAtNxAgain, equalTo(0L)); + + Long pexpireTimeAfterNxAgain = exec(commandObjects.pexpireTime(key)); + assertThat(pexpireTimeAfterNxAgain, equalTo(laterFutureTimestampMillis)); + } + + @Test + public void testTtl() { + String key = "ttlKey"; + String value = "value"; + + long seconds = 10; + + exec(commandObjects.set(key, value)); + exec(commandObjects.expire(key, seconds)); + + Long ttl = exec(commandObjects.ttl(key)); + assertThat(ttl, greaterThan(0L)); + } + + @Test + public void testTtlBinary() { + byte[] key = "ttlKey".getBytes(); + byte[] value = "value".getBytes(); + + long seconds = 10; + + exec(commandObjects.set(key, value)); + exec(commandObjects.expire(key, seconds)); + + Long ttl = exec(commandObjects.ttl(key)); + assertThat(ttl, greaterThan(1L)); + } + + @Test + public void testPttl() { + String key = "pttlKey"; + String value = "value"; + + long milliseconds = 10000; // 10 seconds + + exec(commandObjects.set(key, value)); + exec(commandObjects.pexpire(key, milliseconds)); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(0L)); + } + + @Test + public void testPttlBinary() { + byte[] key = "pttlKey".getBytes(); + byte[] value = "value".getBytes(); + + long milliseconds = 10000; // 10 seconds + + exec(commandObjects.set(key, value)); + exec(commandObjects.pexpire(key, milliseconds)); + + Long pttl = exec(commandObjects.pttl(key)); + assertThat(pttl, greaterThan(1L)); + } + + @Test + public void testTouch() { + String key = "touchKey"; + + exec(commandObjects.set(key, "value")); + + Long touchExisting = exec(commandObjects.touch(key)); + assertThat(touchExisting, equalTo(1L)); + + Long touchNonExistent = exec(commandObjects.touch("nonExistentKey")); + assertThat(touchNonExistent, equalTo(0L)); + } + + @Test + public void testTouchBinary() { + byte[] key = "touchKey".getBytes(); + + exec(commandObjects.set(key, "value".getBytes())); + + Long touchExisting = exec(commandObjects.touch(key)); + assertThat(touchExisting, equalTo(1L)); + + Long touchNonExistent = exec(commandObjects.touch("nonExistentKey".getBytes())); + assertThat(touchNonExistent, equalTo(0L)); + } + + @Test + public void testTouchMultiple() { + String key1 = "touchMultiKey1"; + String key2 = "touchMultiKey2"; + String key3 = "nonExistentKey"; + + exec(commandObjects.set(key1, "value1")); + exec(commandObjects.set(key2, "value2")); + + Long touch = exec(commandObjects.touch(key1, key2, key3)); + assertThat(touch, equalTo(2L)); + } + + @Test + public void testTouchMultipleBinary() { + byte[] key1 = "touchMultiKey1".getBytes(); + byte[] key2 = "touchMultiKey2".getBytes(); + byte[] key3 = "nonExistentKey".getBytes(); + + exec(commandObjects.set(key1, "value1".getBytes())); + exec(commandObjects.set(key2, "value2".getBytes())); + + Long touch = exec(commandObjects.touch(key1, key2, key3)); + assertThat(touch, equalTo(2L)); + } + + @Test + public void testSort() { + String listKey = "sortList"; + + exec(commandObjects.lpush(listKey, "3", "1", "2")); + + List sorted = exec(commandObjects.sort(listKey)); + assertThat(sorted, contains("1", "2", "3")); + } + + @Test + public void testSortBinary() { + byte[] listKey = "sortList".getBytes(); + + exec(commandObjects.lpush(listKey, "3".getBytes(), "1".getBytes(), "2".getBytes())); + + List sorted = exec(commandObjects.sort(listKey)); + assertThat(sorted, contains("1".getBytes(), "2".getBytes(), "3".getBytes())); + } -/** - * Tests related to Generic commands. - */ -public class CommandObjectsGenericCommandsTest extends CommandObjectsStandaloneTestBase { + @Test + public void testSortWithSortingParams() { + String listKey = "sortListParams"; - public CommandObjectsGenericCommandsTest(RedisProtocol protocol) { - super(protocol); + exec(commandObjects.lpush(listKey, "item3", "item1", "item2")); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + List sorted = exec(commandObjects.sort(listKey, sortingParams)); + assertThat(sorted, contains("item1", "item2")); + } + + @Test + public void testSortBinaryWithSortingParams() { + byte[] listKey = "sortListParams".getBytes(); + + exec(commandObjects.lpush(listKey, "item3".getBytes(), "item1".getBytes(), "item2".getBytes())); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + List sorted = exec(commandObjects.sort(listKey, sortingParams)); + assertThat(sorted, contains("item1".getBytes(), "item2".getBytes())); + } + + @Test + public void testSortAndStore() { + String listKey = "sortStoreList"; + String destinationKey = "sortedList"; + + exec(commandObjects.lpush(listKey, "9", "3", "6")); + + Long sort = exec(commandObjects.sort(listKey, destinationKey)); + assertThat(sort, equalTo(3L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("3", "6", "9")); + } + + @Test + public void testSortAndStoreBinary() { + byte[] listKey = "sortStoreList".getBytes(); + byte[] destinationKey = "sortedList".getBytes(); + + exec(commandObjects.lpush(listKey, "9".getBytes(), "3".getBytes(), "6".getBytes())); + + Long sort = exec(commandObjects.sort(listKey, destinationKey)); + assertThat(sort, equalTo(3L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("3".getBytes(), "6".getBytes(), "9".getBytes())); + } + + @Test + public void testSortWithParamsAndStore() { + String listKey = "sortParamsStoreList"; + String destinationKey = "sortedParamsList"; + + exec(commandObjects.lpush(listKey, "item3", "item1", "item2")); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + Long sort = exec(commandObjects.sort(listKey, sortingParams, destinationKey)); + assertThat(sort, equalTo(2L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("item1", "item2")); + } + + @Test + public void testSortWithParamsAndStoreBinary() { + byte[] listKey = "sortParamsStoreList".getBytes(); + byte[] destinationKey = "sortedParamsList".getBytes(); + + exec(commandObjects.lpush(listKey, "item3".getBytes(), "item1".getBytes(), "item2".getBytes())); + + SortingParams sortingParams = new SortingParams().alpha().limit(0, 2); + + Long sort = exec(commandObjects.sort(listKey, sortingParams, destinationKey)); + assertThat(sort, equalTo(2L)); + + List sorted = exec(commandObjects.lrange(destinationKey, 0, -1)); + assertThat(sorted, contains("item1".getBytes(), "item2".getBytes())); + } + + @Test + public void testSortReadonly() { + String listKey = "readonlySortList"; + + exec(commandObjects.lpush(listKey, "3", "1", "2")); + + SortingParams sortingParams = new SortingParams().desc(); + + List sorted = exec(commandObjects.sortReadonly(listKey, sortingParams)); + assertThat(sorted, contains("3", "2", "1")); + } + + @Test + public void testSortReadonlyBinary() { + byte[] listKey = "readonlySortList".getBytes(); + + exec(commandObjects.lpush(listKey, "3".getBytes(), "1".getBytes(), "2".getBytes())); + + SortingParams sortingParams = new SortingParams().desc(); + + List sorted = exec(commandObjects.sortReadonly(listKey, sortingParams)); + assertThat(sorted, contains("3".getBytes(), "2".getBytes(), "1".getBytes())); + } + + @Test + public void testDel() { + String key = "delKey"; + String value = "value"; + + exec(commandObjects.set(key, value)); + + String getBeforeDel = exec(commandObjects.get(key)); + assertThat(getBeforeDel, equalTo(value)); + + Long del = exec(commandObjects.del(key)); + assertThat(del, equalTo(1L)); + + String getAfterDel = exec(commandObjects.get(key)); + assertThat(getAfterDel, nullValue()); + } + + @Test + public void testDelBinary() { + byte[] key = "delKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(key, value)); + + byte[] getBeforeDel = exec(commandObjects.get(key)); + assertThat(getBeforeDel, equalTo(value)); + + Long del = exec(commandObjects.del(key)); + assertThat(del, equalTo(1L)); + + byte[] getAfterDel = exec(commandObjects.get(key)); + assertThat(getAfterDel, nullValue()); + } + + @Test + public void testDelMultiple() { + String key1 = "key1"; + String key2 = "key2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Long del = exec(commandObjects.del(key1, key2, "nonExistingKey")); + assertThat(del, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testDelMultipleBinary() { + byte[] key1 = "key1".getBytes(); + byte[] key2 = "key2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Long del = exec(commandObjects.del(key1, key2, "nonExistingKey".getBytes())); + assertThat(del, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testUnlink() { + String key = "unlinkKey"; + + exec(commandObjects.set(key, "value")); + + Long unlink = exec(commandObjects.unlink(key)); + assertThat(unlink, equalTo(1L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + } + + @Test + public void testUnlinkBinary() { + byte[] key = "unlinkKey".getBytes(); + + exec(commandObjects.set(key, "value".getBytes())); + + Long unlink = exec(commandObjects.unlink(key)); + assertThat(unlink, equalTo(1L)); + + Boolean exists = exec(commandObjects.exists(key)); + assertThat(exists, equalTo(false)); + } + + @Test + public void testUnlinkMultiple() { + String key1 = "key1ToUnlink"; + String key2 = "key2ToUnlink"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Long unlink = exec(commandObjects.unlink(key1, key2, "nonExistingKey")); + assertThat(unlink, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testUnlinkMultipleBinary() { + byte[] key1 = "key1ToUnlink".getBytes(); + byte[] key2 = "key2ToUnlink".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Long unlink = exec(commandObjects.unlink(key1, key2, "nonExistingKey".getBytes())); + assertThat(unlink, equalTo(2L)); + + Long exists = exec(commandObjects.exists(key1, key2)); + assertThat(exists, equalTo(0L)); + } + + @Test + public void testCopyWithStringKeys() { + String srcKey = "sourceKey"; + String dstKey = "destinationKey"; + String value = "value"; + String otherValue = "otherValue"; + + exec(commandObjects.set(srcKey, value)); + + String initialValue = exec(commandObjects.get(srcKey)); + assertThat(initialValue, equalTo(value)); + + String dstBeforeCopy = exec(commandObjects.get(dstKey)); + assertThat(dstBeforeCopy, nullValue()); + + Boolean copy = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copy, equalTo(true)); + + String dstAfterCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterCopy, equalTo(value)); + + exec(commandObjects.set(srcKey, otherValue)); + + Boolean copyFail = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copyFail, equalTo(false)); + + String dstAfterFailedCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterFailedCopy, equalTo(value)); + + Boolean copyReplace = exec(commandObjects.copy(srcKey, dstKey, true)); + assertThat(copyReplace, equalTo(true)); + + String dstAfterReplace = exec(commandObjects.get(dstKey)); + assertThat(dstAfterReplace, equalTo(otherValue)); + } + + @Test + public void testCopyWithBinaryKeys() { + byte[] srcKey = "sourceKey".getBytes(); + byte[] dstKey = "destinationKey".getBytes(); + byte[] value = "value".getBytes(); + byte[] otherValue = "otherValue".getBytes(); + + exec(commandObjects.set(srcKey, value)); + + byte[] initialValue = exec(commandObjects.get(srcKey)); + assertThat(initialValue, equalTo(value)); + + byte[] dstBeforeCopy = exec(commandObjects.get(dstKey)); + assertThat(dstBeforeCopy, nullValue()); + + Boolean copy = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copy, equalTo(true)); + + byte[] dstAfterCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterCopy, equalTo(value)); + + exec(commandObjects.set(srcKey, otherValue)); + + Boolean copyFail = exec(commandObjects.copy(srcKey, dstKey, false)); + assertThat(copyFail, equalTo(false)); + + byte[] dstAfterFailedCopy = exec(commandObjects.get(dstKey)); + assertThat(dstAfterFailedCopy, equalTo(value)); + + Boolean copyReplace = exec(commandObjects.copy(srcKey, dstKey, true)); + assertThat(copyReplace, equalTo(true)); + + byte[] dstAfterReplace = exec(commandObjects.get(dstKey)); + assertThat(dstAfterReplace, equalTo(otherValue)); } @Test - public void testCopy() { + public void testCopyToDb() { String srcKey = "sourceKey"; String dstKey = "destinationKey"; int dstDB = 1; @@ -43,7 +1054,7 @@ public void testCopy() { } @Test - public void testCopyBinary() { + public void testCopyToDbBinary() { String srcKey = "sourceKey"; String dstKey = "destinationKey"; int dstDB = 1; @@ -78,4 +1089,336 @@ private void assertKeyExists(int dstDb, String key, Object expectedValue) { } } + @Test + public void testRenameWithStringKeys() { + String oldKey = "oldKeyName"; + String newKey = "newKeyName"; + String value = "value"; + + exec(commandObjects.set(oldKey, value)); + + String oldValue = exec(commandObjects.get(oldKey)); + assertThat(oldValue, equalTo(value)); + + String newKeyBeforeRename = exec(commandObjects.get(newKey)); + assertThat(newKeyBeforeRename, nullValue()); + + String rename = exec(commandObjects.rename(oldKey, newKey)); + assertThat(rename, equalTo("OK")); + + String oldKeyAfterRename = exec(commandObjects.get(oldKey)); + assertThat(oldKeyAfterRename, nullValue()); + + String newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + } + + @Test + public void testRenameWithBinaryKeys() { + byte[] oldKey = "oldKeyName".getBytes(); + byte[] newKey = "newKeyName".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(oldKey, value)); + + byte[] oldValue = exec(commandObjects.get(oldKey)); + assertThat(oldValue, equalTo(value)); + + byte[] newKeyBeforeRename = exec(commandObjects.get(newKey)); + assertThat(newKeyBeforeRename, nullValue()); + + String rename = exec(commandObjects.rename(oldKey, newKey)); + assertThat(rename, equalTo("OK")); + + byte[] oldKeyAfterRename = exec(commandObjects.get(oldKey)); + assertThat(oldKeyAfterRename, nullValue()); + + byte[] newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + } + + @Test + public void testRenamenx() { + String oldKey = "oldKeyToRenameNX"; + String newKey = "newKeyForRenameNX"; + String anotherKey = "anotherKey"; + String value = "value"; + + exec(commandObjects.set(oldKey, value)); + exec(commandObjects.set(anotherKey, value)); + + String newKeyBefore = exec(commandObjects.get(newKey)); + assertThat(newKeyBefore, nullValue()); + + Long renamenx = exec(commandObjects.renamenx(oldKey, newKey)); + assertThat(renamenx, equalTo(1L)); + + String newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + + Long renamenxFail = exec(commandObjects.renamenx(anotherKey, newKey)); + assertThat(renamenxFail, equalTo(0L)); + + String anotherKeyStillExists = exec(commandObjects.get(anotherKey)); + assertThat(anotherKeyStillExists, equalTo(value)); + } + + @Test + public void testRenamenxBinary() { + byte[] oldKey = "oldKeyToRenameNX".getBytes(); + byte[] newKey = "newKeyForRenameNX".getBytes(); + byte[] anotherKey = "anotherKey".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(oldKey, value)); + exec(commandObjects.set(anotherKey, value)); + + byte[] newKeyBefore = exec(commandObjects.get(newKey)); + assertThat(newKeyBefore, nullValue()); + + Long renamenx = exec(commandObjects.renamenx(oldKey, newKey)); + assertThat(renamenx, equalTo(1L)); + + byte[] newValue = exec(commandObjects.get(newKey)); + assertThat(newValue, equalTo(value)); + + Long renamenxFail = exec(commandObjects.renamenx(anotherKey, newKey)); + assertThat(renamenxFail, equalTo(0L)); + + byte[] anotherKeyStillExists = exec(commandObjects.get(anotherKey)); + assertThat(anotherKeyStillExists, equalTo(value)); + } + + @Test + public void testDbSize() { + Long initialSize = exec(commandObjects.dbSize()); + assertThat(initialSize, greaterThanOrEqualTo(0L)); + + String key = "testKey"; + + exec(commandObjects.set(key, "testValue")); + + Long newSize = exec(commandObjects.dbSize()); + assertThat(newSize, equalTo(initialSize + 1)); + + exec(commandObjects.del(key)); + + Long finalSize = exec(commandObjects.dbSize()); + assertThat(finalSize, equalTo(initialSize)); + } + + @Test + public void testKeysWithStringPattern() { + String pattern = "testKey:*"; + String matchingKey1 = "testKey:1"; + String matchingKey2 = "testKey:2"; + String value = "value"; + + exec(commandObjects.set(matchingKey1, value)); + exec(commandObjects.set(matchingKey2, value)); + exec(commandObjects.set("otherKey", value)); + + Set keys = exec(commandObjects.keys(pattern)); + assertThat(keys, containsInAnyOrder(matchingKey1, matchingKey2)); + + exec(commandObjects.del(matchingKey1, matchingKey2)); + + Set keysAfterDeletion = exec(commandObjects.keys(pattern)); + assertThat(keysAfterDeletion, empty()); + } + + @Test + public void testKeysWithBinaryPattern() { + byte[] pattern = "testKey:*".getBytes(); + byte[] matchingKey1 = "testKey:1".getBytes(); + byte[] matchingKey2 = "testKey:2".getBytes(); + byte[] value = "value".getBytes(); + + exec(commandObjects.set(matchingKey1, value)); + exec(commandObjects.set(matchingKey2, value)); + exec(commandObjects.set("otherKey".getBytes(), value)); + + Set keys = exec(commandObjects.keys(pattern)); + assertThat(keys, containsInAnyOrder(matchingKey1, matchingKey2)); + + exec(commandObjects.del(matchingKey1, matchingKey2)); + + Set keysAfterDeletion = exec(commandObjects.keys(pattern)); + assertThat(keysAfterDeletion, empty()); + } + + @Test + public void testScan() { + String key1 = "scanKey1"; + String key2 = "scanKey2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String nextCursor = "0"; + + do { + scanResult = exec(commandObjects.scan(nextCursor)); + nextCursor = scanResult.getCursor(); + collectedKeys.addAll(scanResult.getResult()); + } while (!"0".equals(nextCursor)); + + assertThat(collectedKeys, hasItems(key1, key2)); + } + + @Test + public void testScanBinary() { + byte[] key1 = "scanKey1".getBytes(); + byte[] key2 = "scanKey2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor)); + cursor = scanResult.getCursorAsBytes(); + collectedKeys.addAll(scanResult.getResult()); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItems(key1, key2)); + } + + @Test + public void testScanWithParams() { + String matchingKey1 = "user:123"; + String matchingKey2 = "user:456"; + String nonMatchingKey = "config:123"; + + exec(commandObjects.set(matchingKey1, "testValue")); + exec(commandObjects.set(matchingKey2, "testValue")); + exec(commandObjects.set(nonMatchingKey, "testValue")); + + ScanParams params = new ScanParams().match("user:*").count(2); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String cursor = "0"; + + do { + scanResult = exec(commandObjects.scan(cursor, params)); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursor(); + } while (!"0".equals(scanResult.getCursor())); + + assertThat(collectedKeys, hasItems(matchingKey1, matchingKey2)); + assertThat(collectedKeys, not(hasItem(nonMatchingKey))); + } + + @Test + public void testScanWithParamsBinary() { + byte[] matchingKey1 = "user:123".getBytes(); + byte[] matchingKey2 = "user:456".getBytes(); + byte[] nonMatchingKey = "config:123".getBytes(); + + exec(commandObjects.set(matchingKey1, "testValue".getBytes())); + exec(commandObjects.set(matchingKey2, "testValue".getBytes())); + exec(commandObjects.set(nonMatchingKey, "testValue".getBytes())); + + ScanParams params = new ScanParams().match("user:*").count(2); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor, params)); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursorAsBytes(); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItems(matchingKey1, matchingKey2)); + assertThat(collectedKeys, not(hasItem(nonMatchingKey))); + } + + @Test + public void testScanWithParamsAndType() { + String stringKey = "user:string:1"; + String listKey = "user:list:1"; + + exec(commandObjects.set(stringKey, "value")); + exec(commandObjects.rpush(listKey, "value1", "value2")); + + ScanParams params = new ScanParams().match("user:*"); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + String cursor = "0"; + + do { + scanResult = exec(commandObjects.scan(cursor, params, "string")); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursor(); + } while (!"0".equals(scanResult.getCursor())); + + assertThat(collectedKeys, hasItem(stringKey)); + assertThat(collectedKeys, not(hasItem(listKey))); + } + + @Test + public void testScanWithParamsAndTypeBinary() { + byte[] stringKey = "user:string:1".getBytes(); + byte[] listKey = "user:list:1".getBytes(); + + exec(commandObjects.set(stringKey, "value".getBytes())); + exec(commandObjects.rpush(listKey, "value1".getBytes(), "value2".getBytes())); + + ScanParams params = new ScanParams().match("user:*".getBytes()); + + Set collectedKeys = new HashSet<>(); + + ScanResult scanResult; + byte[] cursor = "0".getBytes(); + + do { + scanResult = exec(commandObjects.scan(cursor, params, "string".getBytes())); + collectedKeys.addAll(scanResult.getResult()); + cursor = scanResult.getCursorAsBytes(); + } while (!Arrays.equals("0".getBytes(), cursor)); + + assertThat(collectedKeys, hasItem(stringKey)); + assertThat(collectedKeys, not(hasItem(listKey))); + } + + @Test + public void testRandomKey() { + String key1 = "testKey1"; + String key2 = "testKey2"; + + exec(commandObjects.set(key1, "value")); + exec(commandObjects.set(key2, "value")); + + String randomKey = exec(commandObjects.randomKey()); + + assertThat(randomKey, anyOf(equalTo(key1), equalTo(key2))); + } + + @Test + public void testRandomBinaryKey() { + byte[] key1 = "testKey1".getBytes(); + byte[] key2 = "testKey2".getBytes(); + + exec(commandObjects.set(key1, "value".getBytes())); + exec(commandObjects.set(key2, "value".getBytes())); + + byte[] randomBinaryKey = exec(commandObjects.randomBinaryKey()); + + assertThat(randomBinaryKey, anyOf(equalTo(key1), equalTo(key2))); + } + } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java index d1b1eaacaa..4fd7c60fc4 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSearchAndQueryCommandsTest.java @@ -1,19 +1,29 @@ package redis.clients.jedis.commands.commandobjects; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.equalToIgnoringCase; import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; 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 static org.hamcrest.Matchers.nullValue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import org.json.JSONObject; @@ -21,8 +31,12 @@ import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.SortingOrder; import redis.clients.jedis.json.Path2; +import redis.clients.jedis.resps.Tuple; import redis.clients.jedis.search.Document; +import redis.clients.jedis.search.FTCreateParams; import redis.clients.jedis.search.FTSearchParams; +import redis.clients.jedis.search.FTSpellCheckParams; +import redis.clients.jedis.search.IndexDataType; import redis.clients.jedis.search.IndexDefinition; import redis.clients.jedis.search.IndexOptions; import redis.clients.jedis.search.Query; @@ -31,6 +45,10 @@ import redis.clients.jedis.search.aggr.AggregationBuilder; import redis.clients.jedis.search.aggr.AggregationResult; import redis.clients.jedis.search.aggr.Reducers; +import redis.clients.jedis.search.schemafields.NumericField; +import redis.clients.jedis.search.schemafields.SchemaField; +import redis.clients.jedis.search.schemafields.TagField; +import redis.clients.jedis.search.schemafields.TextField; /** * Tests related to Search and query commands. @@ -169,6 +187,108 @@ public void testFtSearchJson() { assertThat(document.get("$"), equalTo("{\"title\":\"Redis in Action\",\"price\":17.99,\"author\":\"John Doe\"}")); } + @Test + public void testFtCreateWithParams() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title").as("title"), + NumericField.of("$.price").as("price") + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookRedisInAction = new JSONObject(); + bookRedisInAction.put("title", "Redis in Action"); + bookRedisInAction.put("price", 17.99); + bookRedisInAction.put("author", "John Doe"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookRedisInAction)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookRedisEssentials = new JSONObject(); + bookRedisEssentials.put("title", "Redis Essentials"); + bookRedisEssentials.put("price", 19.99); + bookRedisEssentials.put("author", "Jane Doe"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookRedisEssentials)); + 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")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookRedisInAction)); + } + + @Test + public void testFtAlterWithParams() throws InterruptedException { + String indexName = "booksIndex"; + + List schema = new ArrayList<>(); + schema.add(TextField.of("$.title").as("title")); + schema.add(NumericField.of("$.price").as("price")); + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, schema)); + assertThat(createResult, equalTo("OK")); + + JSONObject bookRedisInAction = new JSONObject(); + bookRedisInAction.put("title", "Redis in Action"); + bookRedisInAction.put("price", 17.99); + bookRedisInAction.put("author", "John Doe"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookRedisInAction)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookRedisEssentials = new JSONObject(); + bookRedisEssentials.put("title", "Redis Essentials"); + bookRedisEssentials.put("price", 19.99); + bookRedisEssentials.put("author", "Jane Doe"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookRedisEssentials)); + assertThat(jsonSet2, equalTo("OK")); + + SearchResult searchNotInIndex = exec(commandObjects.ftSearch(indexName, "John")); + + assertThat(searchNotInIndex.getTotalResults(), equalTo(0L)); + assertThat(searchNotInIndex.getDocuments(), empty()); + + List schemaExtension = new ArrayList<>(); + schemaExtension.add(TextField.of("$.author").as("author")); + + String alter = exec(commandObjects.ftAlter(indexName, schemaExtension)); + assertThat(alter, equalTo("OK")); + + Thread.sleep(300); // wait for index to be updated + + SearchResult searchInIndex = exec(commandObjects.ftSearch(indexName, "John")); + + assertThat(searchInIndex.getTotalResults(), equalTo(1L)); + assertThat(searchInIndex.getDocuments(), hasSize(1)); + + Document document = searchInIndex.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookRedisInAction)); + } + @Test public void testFtExplain() { String indexName = "booksIndex"; @@ -252,4 +372,213 @@ public void testFtAggregate() { assertThat(result, hasEntry("genre", "Technology")); assertThat(result, hasEntry("avgPrice", "23.49")); } + + @Test + public void testSpellCheck() { + // Add some terms to an index + String indexName = "techArticles"; + + List schemaFields = Collections.singletonList(TextField.of("$.technology")); + exec(commandObjects.ftCreate(indexName, FTCreateParams.createParams().on(IndexDataType.JSON), schemaFields)); + + exec(commandObjects.jsonSet("articles:02", Path2.ROOT_PATH, new JSONObject().put("technology", "Flutter"))); + exec(commandObjects.jsonSet("articles:03", Path2.ROOT_PATH, new JSONObject().put("technology", "Rust"))); + exec(commandObjects.jsonSet("articles:04", Path2.ROOT_PATH, new JSONObject().put("technology", "Angular"))); + + SearchResult searchInIndex = exec(commandObjects.ftSearch(indexName, "Flutter")); + assertThat(searchInIndex.getTotalResults(), equalTo(1L)); + + String query = "Fluter JavaScrit Pyhton Rust"; + + // Spellcheck based on index only + Map> indexOnly = exec(commandObjects.ftSpellCheck(indexName, query)); + assertThat(indexOnly.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexOnly.get("javascrit"), anEmptyMap()); + assertThat(indexOnly.get("pyhton"), anEmptyMap()); + + // Add more terms to a dictionary + String dictionary = "techDict"; + + Long addResult = exec(commandObjects.ftDictAdd(dictionary, "JavaScript", "Python")); + assertThat(addResult, equalTo(2L)); + + // Spellcheck based on index and dictionary + FTSpellCheckParams paramsWithDict = new FTSpellCheckParams().includeTerm(dictionary); + + Map> indexAndDictionary = exec(commandObjects.ftSpellCheck(indexName, query, paramsWithDict)); + assertThat(indexAndDictionary.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexAndDictionary.get("javascrit"), hasKey("JavaScript")); + assertThat(indexAndDictionary.get("pyhton"), anEmptyMap()); + + // Increase Levenshtein distance, to allow for misspelled letter + FTSpellCheckParams paramsWithDictAndDist = new FTSpellCheckParams().includeTerm(dictionary).distance(2); + + Map> indexAndDictionaryWithDist = exec(commandObjects.ftSpellCheck(indexName, query, paramsWithDictAndDist)); + assertThat(indexAndDictionaryWithDist.get("fluter"), hasKey(equalToIgnoringCase("Flutter"))); + assertThat(indexAndDictionaryWithDist.get("javascrit"), hasKey("JavaScript")); + assertThat(indexAndDictionaryWithDist.get("pyhton"), hasKey("Python")); + } + + @Test + public void testFtDictAddDelAndDump() { + String dictionary = "programmingLanguages"; + + Long addResult = exec(commandObjects.ftDictAdd(dictionary, "Java", "Python", "JavaScript", "Rust")); + assertThat(addResult, equalTo(4L)); + + Set dumpResultAfterAdd = exec(commandObjects.ftDictDump(dictionary)); + assertThat(dumpResultAfterAdd, containsInAnyOrder("Java", "Python", "JavaScript", "Rust")); + + Long delResult = exec(commandObjects.ftDictDel(dictionary, "Rust")); + assertThat(delResult, equalTo(1L)); + + Set dumpResultAfterDel = exec(commandObjects.ftDictDump(dictionary)); + assertThat(dumpResultAfterDel, containsInAnyOrder("Java", "Python", "JavaScript")); + } + + @Test + public void testFtDictAddDelAndDumpWithSampleKeys() { + String index = "index"; // not used actually, but needed for the command + + String dictionary = "programmingLanguages"; + + Long addResult = exec(commandObjects.ftDictAddBySampleKey(index, dictionary, "Java", "Python", "JavaScript", "Rust")); + assertThat(addResult, equalTo(4L)); + + Set dumpResultAfterAdd = exec(commandObjects.ftDictDumpBySampleKey(index, dictionary)); + assertThat(dumpResultAfterAdd, containsInAnyOrder("Java", "Python", "JavaScript", "Rust")); + + Long delResult = exec(commandObjects.ftDictDelBySampleKey(index, dictionary, "Rust")); + assertThat(delResult, equalTo(1L)); + + Set dumpResultAfterDel = exec(commandObjects.ftDictDumpBySampleKey(index, dictionary)); + assertThat(dumpResultAfterDel, containsInAnyOrder("Java", "Python", "JavaScript")); + } + + @Test + public void testFtTags() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title"), + TagField.of("$.genre").as("genre").separator(',') + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookDune = new JSONObject(); + bookDune.put("title", "Dune"); + bookDune.put("genre", "Science Fiction, Fantasy, Adventure"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookDune)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookTheFoundation = new JSONObject(); + bookTheFoundation.put("title", "The Foundation"); + bookTheFoundation.put("genre", "Technical, Novel, Essential"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookTheFoundation)); + assertThat(jsonSet2, equalTo("OK")); + + Set tagVals = exec(commandObjects.ftTagVals(indexName, "genre")); + assertThat(tagVals, containsInAnyOrder( + "science fiction", "fantasy", "adventure", "technical", "novel", "essential")); + + SearchResult searchSimple = exec(commandObjects.ftSearch(indexName, "Fantasy")); + + assertThat(searchSimple.getTotalResults(), equalTo(0L)); + assertThat(searchSimple.getDocuments(), empty()); + + SearchResult searchSpecialSyntax = exec(commandObjects.ftSearch(indexName, "@genre:{ fantasy }")); + + assertThat(searchSpecialSyntax.getTotalResults(), equalTo(1L)); + assertThat(searchSpecialSyntax.getDocuments(), hasSize(1)); + + Document document = searchSpecialSyntax.getDocuments().get(0); + assertThat(document.getId(), equalTo("books:1000")); + + Object documentRoot = document.get("$"); + assertThat(documentRoot, instanceOf(String.class)); // Unparsed! + assertThat(documentRoot, jsonEquals(bookDune)); + } + + @Test + public void testFtInfo() { + String indexName = "booksIndex"; + + SchemaField[] schema = { + TextField.of("$.title"), + TagField.of("$.genre").as("genre").separator(',') + }; + + FTCreateParams createParams = FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("books:"); + + String createResult = exec(commandObjects.ftCreate(indexName, createParams, Arrays.asList(schema))); + assertThat(createResult, equalTo("OK")); + + JSONObject bookDune = new JSONObject(); + bookDune.put("title", "Dune"); + bookDune.put("genre", "Science Fiction, Fantasy, Adventure"); + + String jsonSet = exec(commandObjects.jsonSet("books:1000", Path2.ROOT_PATH, bookDune)); + assertThat(jsonSet, equalTo("OK")); + + JSONObject bookTheFoundation = new JSONObject(); + bookTheFoundation.put("title", "The Foundation"); + bookTheFoundation.put("genre", "Technical, Novel, Essential"); + + String jsonSet2 = exec(commandObjects.jsonSet("books:1200", Path2.ROOT_PATH, bookTheFoundation)); + assertThat(jsonSet2, equalTo("OK")); + + Map infoResult = exec(commandObjects.ftInfo(indexName)); + assertThat(infoResult, hasEntry("index_name", indexName)); + } + + @Test + public void testFtSugAddAndGet() { + String key = "autocomplete"; + + // Round 1: single suggestion with weight 2.0 + Long sugAdd1 = exec(commandObjects.ftSugAdd(key, "Redis", 2.0)); + assertThat(sugAdd1, equalTo(1L)); + + List suggestionsOneOption = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsOneOption, contains("Redis")); + + List suggestionsWithScoresOneOption = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresOneOption, contains( + new Tuple("Redis", 1.0))); + + // Round 2: two suggestions with weights 2.0 and 1.0 + Long sugAdd2 = exec(commandObjects.ftSugAdd(key, "Redux", 1.0)); + assertThat(sugAdd2, equalTo(2L)); + + List suggestionsTwoOptions = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsTwoOptions, contains("Redis", "Redux")); + + List suggestionsWithScoresTwoOptions = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresTwoOptions, contains( + new Tuple("Redis", 1.0), + new Tuple("Redux", 0.5))); + + // Round 2: same two suggestions with weights 2.0 and 3.0 + Long sugAddIncr = exec(commandObjects.ftSugAddIncr(key, "Redux", 2.0)); + assertThat(sugAddIncr, equalTo(2L)); + + List suggestionsAfterScoreChange = exec(commandObjects.ftSugGet(key, "Re")); + assertThat(suggestionsAfterScoreChange, contains("Redux", "Redis")); + + List suggestionsWithScoresAfterChange = exec(commandObjects.ftSugGetWithScores(key, "Re")); + assertThat(suggestionsWithScoresAfterChange, contains( + new Tuple("Redux", 1.5), + new Tuple("Redis", 1.0))); + } + } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java index cf2be1b0a7..21a573c8db 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java @@ -1470,6 +1470,60 @@ public void testZmpopAndZmpopWithCountBinary() { @Test public void testBzmpop() { + String key1 = "sortedSet1"; + String key2 = "sortedSet2"; + double score1 = 1.0; + double score2 = 2.0; + String member1 = "member1"; + String member2 = "member2"; + double timeout = 0.1; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key1, score2, member2)); + + exec(commandObjects.zadd(key2, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpopMax = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, key1, key2)); + assertThat(bzmpopMax, notNullValue()); + assertThat(bzmpopMax.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMax.getValue(), contains(new Tuple(member2, score2))); + + KeyValue> bzmpopMin = exec(commandObjects.bzmpop(timeout, SortedSetOption.MIN, key1, key2)); + assertThat(bzmpopMin, notNullValue()); + assertThat(bzmpopMin.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMin.getValue(), contains(new Tuple(member1, score1))); + } + + @Test + public void testBzmpopBinary() { + byte[] key1 = "sortedSet1".getBytes(); + byte[] key2 = "sortedSet2".getBytes(); + double score1 = 1.0; + double score2 = 2.0; + byte[] member1 = "member1".getBytes(); + byte[] member2 = "member2".getBytes(); + double timeout = 0.1; + + exec(commandObjects.zadd(key1, score1, member1)); + exec(commandObjects.zadd(key1, score2, member2)); + + exec(commandObjects.zadd(key2, score1, member1)); + exec(commandObjects.zadd(key2, score2, member2)); + + KeyValue> bzmpopMax = exec(commandObjects.bzmpop(timeout, SortedSetOption.MAX, key1, key2)); + assertThat(bzmpopMax, notNullValue()); + assertThat(bzmpopMax.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMax.getValue(), contains(new Tuple(member2, score2))); + + KeyValue> bzmpopMin = exec(commandObjects.bzmpop(timeout, SortedSetOption.MIN, key1, key2)); + assertThat(bzmpopMin, notNullValue()); + assertThat(bzmpopMin.getKey(), anyOf(equalTo(key1), equalTo(key2))); + assertThat(bzmpopMin.getValue(), contains(new Tuple(member1, score1))); + } + + @Test + public void testBzmpopCount() { String key1 = "sortedSet1"; String key2 = "sortedSet2"; double score1 = 1.0; @@ -1488,7 +1542,7 @@ public void testBzmpop() { } @Test - public void testBzmpopBinary() { + public void testBzmpopCountBinary() { byte[] key1 = "sortedSet1".getBytes(); byte[] key2 = "sortedSet2".getBytes(); double score1 = 1.0; diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java index 2978544093..31f7949bba 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java @@ -3,8 +3,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; @@ -24,6 +26,7 @@ import redis.clients.jedis.params.XPendingParams; import redis.clients.jedis.params.XReadGroupParams; import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.params.XTrimParams; import redis.clients.jedis.resps.StreamConsumerInfo; import redis.clients.jedis.resps.StreamConsumersInfo; import redis.clients.jedis.resps.StreamEntry; @@ -568,27 +571,86 @@ public void testXTrimCommands() { Long sizeBeforeTrim = exec(commandObjects.xlen(key)); assertThat(sizeBeforeTrim, equalTo(10L)); - Long xtrim = exec(commandObjects.xtrim(key, 5, false)); - assertThat(xtrim, equalTo(5L)); + Long xtrim = exec(commandObjects.xtrim(key, 6, false)); + assertThat(xtrim, equalTo(4L)); Long sizeAfterTrim = exec(commandObjects.xlen(key)); - assertThat(sizeAfterTrim, equalTo(5L)); + assertThat(sizeAfterTrim, equalTo(6L)); - // 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 xtrimApproximate = exec(commandObjects.xtrim(key, 3, true)); + assertThat(xtrimApproximate, lessThanOrEqualTo(3L)); + + Long sizeAfterApproximateTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterApproximateTrim, greaterThanOrEqualTo(3L)); + } + + @Test + public void testXTrimCommandsBinary() { + String keyStr = "testStream"; + byte[] key = keyStr.getBytes(); + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(keyStr, 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 xtrimBinary = exec(commandObjects.xtrim(key, 6, false)); + assertThat(xtrimBinary, equalTo(4L)); Long sizeAfterBinaryTrim = exec(commandObjects.xlen(key)); - assertThat(sizeAfterBinaryTrim, equalTo(5L)); + assertThat(sizeAfterBinaryTrim, equalTo(6L)); + + Long xtrimApproximateBinary = exec(commandObjects.xtrim(key, 3, true)); + assertThat(xtrimApproximateBinary, lessThanOrEqualTo(3L)); + + Long sizeAfterApproximateBinaryTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterApproximateBinaryTrim, greaterThanOrEqualTo(3L)); + } + + @Test + public void testXTrimWithParams() { + 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)); + + XTrimParams params = new XTrimParams().maxLen(6); + + Long xtrim = exec(commandObjects.xtrim(key, params)); + assertThat(xtrim, equalTo(4L)); + + Long sizeAfterTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterTrim, equalTo(6L)); + } + + @Test + public void testXTrimWithParamsBinary() { + String keyStr = "testStream"; + byte[] key = keyStr.getBytes(); + + // Populate the stream with more entries than we intend to keep + for (int i = 0; i < 10; i++) { + exec(commandObjects.xadd(keyStr, StreamEntryID.NEW_ENTRY, Collections.singletonMap("field" + i, "value" + i))); + } + + Long sizeBeforeTrim = exec(commandObjects.xlen(key)); + assertThat(sizeBeforeTrim, equalTo(10L)); + + XTrimParams params = new XTrimParams().maxLen(6); + + Long xtrimBinary = exec(commandObjects.xtrim(key, params)); + assertThat(xtrimBinary, equalTo(4L)); + + Long sizeAfterTrim = exec(commandObjects.xlen(key)); + assertThat(sizeAfterTrim, equalTo(6L)); } @Test @@ -885,10 +947,10 @@ public void testXInfoConsumersWithActiveConsumers() { 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.xadd(streamKey, (StreamEntryID) null, messageBody1)); + exec(commandObjects.xadd(streamKey, (StreamEntryID) null, messageBody2)); - exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); + exec(commandObjects.xgroupCreate(streamKey, group, null, true)); XReadGroupParams xReadGroupParams = new XReadGroupParams().count(1); Map stream = Collections.singletonMap(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY); From 710dceaaf53cefc0e4e6d9692508124cfd4546c5 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 8 Apr 2024 14:43:50 +0300 Subject: [PATCH 2/2] Separate test for XADD with null Id --- .../CommandObjectsStreamCommandsTest.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java index 31f7949bba..8d01e4283c 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStreamCommandsTest.java @@ -304,6 +304,26 @@ public void testXrevrangeWithBinaryParameters() { assertThat(xrevrangeUnknown, empty()); } + @Test + public void testXaddWithNullId() { + String key = "testStreamWithString"; + + // Add two entries, don't specify the IDs + StreamEntryID firstId = exec(commandObjects.xadd(key, (StreamEntryID) null, Collections.singletonMap("field", "value"))); + assertThat(firstId, notNullValue()); + + StreamEntryID secondId = exec(commandObjects.xadd(key, (StreamEntryID) null, Collections.singletonMap("field", "value"))); + assertThat(secondId, notNullValue()); + + assertThat(secondId, not(equalTo(firstId))); + assertThat(secondId.getSequence(), greaterThanOrEqualTo(firstId.getSequence())); + + List xrangeAll = exec(commandObjects.xrange(key, (StreamEntryID) null, null)); + assertThat(xrangeAll.size(), equalTo(2)); + assertThat(xrangeAll.get(0).getID(), equalTo(firstId)); + assertThat(xrangeAll.get(1).getID(), equalTo(secondId)); + } + @Test public void testXackXpending() { String key = "testStreamForXackEffect"; @@ -947,10 +967,10 @@ public void testXInfoConsumersWithActiveConsumers() { Map messageBody1 = Collections.singletonMap("field1", "value1"); Map messageBody2 = Collections.singletonMap("field2", "value2"); - exec(commandObjects.xadd(streamKey, (StreamEntryID) null, messageBody1)); - exec(commandObjects.xadd(streamKey, (StreamEntryID) null, messageBody2)); + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody1)); + exec(commandObjects.xadd(streamKey, StreamEntryID.NEW_ENTRY, messageBody2)); - exec(commandObjects.xgroupCreate(streamKey, group, null, true)); + exec(commandObjects.xgroupCreate(streamKey, group, new StreamEntryID(), true)); XReadGroupParams xReadGroupParams = new XReadGroupParams().count(1); Map stream = Collections.singletonMap(streamKey, StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY);