From 45627760aab2b064aa0db6f43578ee82ffc123da Mon Sep 17 00:00:00 2001 From: Jennifer Hickey Date: Mon, 17 Jun 2013 13:39:47 -0700 Subject: [PATCH] Add Redis 2.6 bitop and bitcount commands to Connections DATAREDIS-179 --- .../DefaultStringRedisConnection.java | 25 +++++- .../redis/connection/RedisStringCommands.java | 10 +++ .../connection/StringRedisConnection.java | 6 ++ .../connection/jedis/JedisConnection.java | 16 +++- .../connection/jredis/JredisConnection.java | 15 ++++ .../connection/lettuce/LettuceConnection.java | 77 +++++++++++++++++++ .../redis/connection/srp/SrpConnection.java | 42 +++++++++- .../data/redis/connection/srp/SrpUtils.java | 10 +++ .../AbstractConnectionIntegrationTests.java | 72 +++++++++++++++++ ...actConnectionPipelineIntegrationTests.java | 21 +++++ .../JedisConnectionIntegrationTests.java | 40 ++++++++++ ...disConnectionPipelineIntegrationTests.java | 40 ++++++++++ .../JRedisConnectionIntegrationTests.java | 40 ++++++++++ .../LettuceConnectionIntegrationTests.java | 9 +++ ...uceConnectionPipelineIntegrationTests.java | 15 ++++ .../srp/SrpConnectionIntegrationTests.java | 2 - ...ConnectionTransactionIntegrationTests.java | 8 ++ 17 files changed, 443 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 747193b98..e9962a1d9 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -452,6 +452,18 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return delegate.strLen(key); } + public Long bitCount(byte[] key) { + return delegate.bitCount(key); + } + + public Long bitCount(byte[] key, long begin, long end) { + return delegate.bitCount(key, begin, end); + } + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + return delegate.bitOp(op, destination, keys); + } + public void subscribe(MessageListener listener, byte[]... channels) { delegate.subscribe(listener, channels); } @@ -1023,8 +1035,19 @@ public class DefaultStringRedisConnection implements StringRedisConnection { public Long strLen(String key) { return delegate.strLen(serialize(key)); } - + public Long bitCount(String key) { + return delegate.bitCount(serialize(key)); + } + + public Long bitCount(String key, long begin, long end) { + return delegate.bitCount(serialize(key)); + } + + public Long bitOp(BitOperation op, String destination, String... keys) { + return delegate.bitOp(op, serialize(destination), serializeMulti(keys)); + } + public void subscribe(MessageListener listener, String... channels) { delegate.subscribe(listener, serializeMulti(channels)); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java index 69d384445..7a32a7ba3 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java @@ -26,6 +26,10 @@ import java.util.Map; */ public interface RedisStringCommands { + public enum BitOperation { + AND, OR, XOR, NOT; + } + byte[] get(byte[] key); byte[] getSet(byte[] key, byte[] value); @@ -60,5 +64,11 @@ public interface RedisStringCommands { void setBit(byte[] key, long offset, boolean value); + Long bitCount(byte[] key); + + Long bitCount(byte[] key, long begin, long end); + + Long bitOp(BitOperation op, byte[] destination, byte[]... keys); + Long strLen(byte[] key); } diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index 7dee4f5a9..2ca2e415c 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -115,6 +115,12 @@ public interface StringRedisConnection extends RedisConnection { void setBit(String key, long offset, boolean value); + Long bitCount(String key); + + Long bitCount(String key, long begin, long end); + + Long bitOp(BitOperation op, String destination, String... keys); + Long strLen(String key); Long rPush(String key, String value); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 474f98279..9c6a68c51 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -1188,11 +1188,25 @@ public class JedisConnection implements RedisConnection { } } + + public Long bitCount(byte[] key) { + throw new UnsupportedOperationException(); + } + + + public Long bitCount(byte[] key, long begin, long end) { + throw new UnsupportedOperationException(); + } + + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + throw new UnsupportedOperationException(); + } + // // List commands // - public Long lPush(byte[] key, byte[] value) { try { if (isQueueing()) { diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java index 158906c21..b45dae5b8 100644 --- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java @@ -609,6 +609,21 @@ public class JredisConnection implements RedisConnection { throw new UnsupportedOperationException(); } + + public Long bitCount(byte[] key) { + throw new UnsupportedOperationException(); + } + + + public Long bitCount(byte[] key, long begin, long end) { + throw new UnsupportedOperationException(); + } + + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + throw new UnsupportedOperationException(); + } + // // List commands // diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index b32356cd9..cdbf2d599 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -999,6 +999,47 @@ public class LettuceConnection implements RedisConnection { } } + + public Long bitCount(byte[] key) { + try { + if (isPipelined()) { + pipeline(getAsyncConnection().bitcount(key)); + return null; + } + return getConnection().bitcount(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + + public Long bitCount(byte[] key, long begin, long end) { + try { + if (isPipelined()) { + pipeline(getAsyncConnection().bitcount(key, begin, end)); + return null; + } + return getConnection().bitcount(key, begin, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(asyncBitOp(op, destination, keys)); + return null; + } + return syncBitOp(op, destination, keys); + } catch (UnsupportedOperationException ex) { + throw ex; + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + // // List commands // @@ -2024,4 +2065,40 @@ public class LettuceConnection implements RedisConnection { } return txConn; } + + private Future asyncBitOp(BitOperation op, byte[] destination, byte[]... keys) { + switch (op) { + case AND: + return getAsyncConnection().bitopAnd(destination, keys); + case OR: + return getAsyncConnection().bitopOr(destination, keys); + case XOR: + return getAsyncConnection().bitopXor(destination, keys); + case NOT: + if (keys.length != 1) { + throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + } + return getAsyncConnection().bitopNot(destination, keys[0]); + default: + throw new UnsupportedOperationException("Bit operation " + op + " is not supported"); + } + } + + private Long syncBitOp(BitOperation op, byte[] destination, byte[]... keys) { + switch (op) { + case AND: + return getConnection().bitopAnd(destination, keys); + case OR: + return getConnection().bitopOr(destination, keys); + case XOR: + return getConnection().bitopXor(destination, keys); + case NOT: + if (keys.length != 1) { + throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + } + return getConnection().bitopNot(destination, keys[0]); + default: + throw new UnsupportedOperationException("Bit operation " + op + " is not supported"); + } + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java index 00298a0d2..65f03cc84 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java @@ -68,6 +68,7 @@ public class SrpConnection implements RedisConnection { private PipelineTracker callback; private volatile SrpSubscription subscription; + @SuppressWarnings("rawtypes") private static class PipelineTracker implements FutureCallback { private final List results = Collections.synchronizedList(new ArrayList()); @@ -954,11 +955,49 @@ public class SrpConnection implements RedisConnection { } } + + public Long bitCount(byte[] key) { + try { + if (isPipelined()) { + pipeline(pipeline.bitcount(key, 0, -1)); + return null; + } + return client.bitcount(key, 0, -1).data(); + } catch (Exception ex) { + throw convertSrpAccessException(ex); + } + } + + + public Long bitCount(byte[] key, long begin, long end) { + try { + if (isPipelined()) { + pipeline(pipeline.bitcount(key, begin, end)); + return null; + } + return client.bitcount(key, begin, end).data(); + } catch (Exception ex) { + throw convertSrpAccessException(ex); + } + } + + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(pipeline.bitop(SrpUtils.bitOp(op), destination, (Object[]) keys)); + return null; + } + return client.bitop(SrpUtils.bitOp(op), destination, (Object[])keys).data(); + } catch (Exception ex) { + throw convertSrpAccessException(ex); + } + } + // // List commands // - public Long lPush(byte[] key, byte[] value) { try { if (isPipelined()) { @@ -1932,6 +1971,7 @@ public class SrpConnection implements RedisConnection { } // processing method that adds a listener to the future in order to track down the results and close the pipeline + @SuppressWarnings("rawtypes") private void pipeline(ListenableFuture future) { callback.addCommand(future); } diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpUtils.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpUtils.java index a54470e1f..c47a074be 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpUtils.java @@ -30,6 +30,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisListCommands.Position; +import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters; import org.springframework.util.Assert; @@ -83,6 +84,7 @@ abstract class SrpUtils { return info; } + @SuppressWarnings("rawtypes") static List toBytesList(Reply[] replies) { if(replies == null) { return null; @@ -106,6 +108,7 @@ abstract class SrpUtils { return Arrays.asList(byteArrays); } + @SuppressWarnings("rawtypes") static Set toSet(Reply[] byteArrays) { return new LinkedHashSet(toBytesList(byteArrays)); } @@ -142,6 +145,7 @@ abstract class SrpUtils { return convertTuple(zrange.data()); } + @SuppressWarnings("rawtypes") static Set convertTuple(Reply[] byteArrays) { Set tuples = new LinkedHashSet(byteArrays.length / 2 + 1); @@ -168,6 +172,7 @@ abstract class SrpUtils { return args; } + @SuppressWarnings("rawtypes") static Map toMap(Reply[] byteArrays) { Map map = new LinkedHashMap(byteArrays.length / 2); for (int i = 0; i < byteArrays.length; i++) { @@ -263,4 +268,9 @@ abstract class SrpUtils { return arrays.toArray(); } + + static byte[] bitOp(BitOperation op) { + Assert.notNull(op, "The bit operation is required"); + return op.name().toUpperCase().getBytes(Charsets.UTF_8); + } } \ No newline at end of file diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index 5f8e4caf5..1434ad7de 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -49,6 +49,7 @@ import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.RedisTestProfileValueSource; import org.springframework.data.redis.TestCondition; import org.springframework.data.redis.connection.RedisListCommands.Position; +import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.SortParameters.Order; @@ -227,6 +228,77 @@ public abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(new Object[] { false, true }), actual); } + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitCount() { + String key = "bitset-test"; + connection.setBit(key, 0, false); + connection.setBit(key, 1, true); + connection.setBit(key, 2, true); + actual.add(connection.bitCount(key)); + verifyResults(new ArrayList(Collections.singletonList(2l)), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitCountInterval() { + connection.set("mykey", "foobar"); + actual.add(connection.bitCount("mykey", 1, 1)); + verifyResults(new ArrayList(Collections.singletonList(26l)), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitCountNonExistentKey() { + actual.add(connection.bitCount("mykey")); + verifyResults(new ArrayList(Collections.singletonList(0l)), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpAnd() { + connection.set("key1", "foo"); + connection.set("key2", "bar"); + actual.add(connection.bitOp(BitOperation.AND, "key3", "key1", "key2")); + actual.add(connection.get("key3")); + verifyResults(Arrays.asList(new Object[] { 3l, "bab" }), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpOr() { + connection.set("key1", "foo"); + connection.set("key2", "ugh"); + actual.add(connection.bitOp(BitOperation.OR, "key3", "key1", "key2")); + actual.add(connection.get("key3")); + verifyResults(Arrays.asList(new Object[] { 3l, "woo" }), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpXOr() { + connection.set("key1", "abcd"); + connection.set("key2", "efgh"); + actual.add(connection.bitOp(BitOperation.XOR, "key3", "key1", "key2")); + verifyResults(Arrays.asList(new Object[] { 4l }), actual); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNot() { + connection.set("key1", "abcd"); + actual.add(connection.bitOp(BitOperation.NOT, "key3", "key1")); + verifyResults(Arrays.asList(new Object[] { 4l }), actual); + } + + @Test(expected=RedisSystemException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNotMultipleSources() { + connection.set("key1", "abcd"); + connection.set("key2", "efgh"); + actual.add(connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); + } + @Test public void testInfo() throws Exception { Properties info = connection.info(); diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java index 9f4cc6799..f5c734937 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java @@ -38,6 +38,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.springframework.data.redis.TestCondition; +import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; @@ -262,6 +263,26 @@ abstract public class AbstractConnectionPipelineIntegrationTests extends verifyResults(Arrays.asList(new Object[] { 0l, 0l, 0l, 1l }), actual); } + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitCount() { + String key = "bitset-test"; + connection.setBit(key, 0, false); + connection.setBit(key, 1, true); + connection.setBit(key, 2, true); + actual.add(connection.bitCount(key)); + verifyResults(Arrays.asList(new Object[] { 0l, 0l, 0l, 2l }), actual); + } + + @Test(expected=RedisPipelineException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNotMultipleSources() { + connection.set("key1", "abcd"); + connection.set("key2", "efgh"); + actual.add(connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); + getResults(); + } + @Test public void testDbSize() { connection.set("dbparam", "foo"); diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java index 0a6727774..ee6b0c0aa 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionIntegrationTests.java @@ -105,6 +105,46 @@ public class JedisConnectionIntegrationTests extends AbstractConnectionIntegrati super.testRestoreTtl(); } + @Test(expected=UnsupportedOperationException.class) + public void testBitCount() { + super.testBitCount(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountInterval() { + super.testBitCountInterval(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountNonExistentKey() { + super.testBitCountNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpAnd() { + super.testBitOpAnd(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpOr() { + super.testBitOpOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpXOr() { + super.testBitOpXOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNot() { + super.testBitOpNot(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNotMultipleSources() { + super.testBitOpNotMultipleSources(); + } + @Test public void testIncrDecrByLong() { String key = "test.count"; diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java index 70b592ec5..94a6904c6 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java @@ -152,6 +152,46 @@ public class JedisConnectionPipelineIntegrationTests extends super.testBitSet(); } + @Test(expected=UnsupportedOperationException.class) + public void testBitCount() { + connection.bitCount("foo"); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountInterval() { + super.testBitCountInterval(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountNonExistentKey() { + super.testBitCountNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpAnd() { + super.testBitOpAnd(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpOr() { + super.testBitOpOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpXOr() { + super.testBitOpXOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNot() { + super.testBitOpNot(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNotMultipleSources() { + super.testBitOpNotMultipleSources(); + } + @Test(expected = RedisSystemException.class) public void testRandomKey() { super.testRandomKey(); diff --git a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java index 724b383a0..8c9507cad 100644 --- a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java @@ -343,6 +343,46 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat super.testRestoreTtl(); } + @Test(expected=UnsupportedOperationException.class) + public void testBitCount() { + super.testBitCount(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountInterval() { + super.testBitCountInterval(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitCountNonExistentKey() { + super.testBitCountNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpAnd() { + super.testBitOpAnd(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpOr() { + super.testBitOpOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpXOr() { + super.testBitOpXOr(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNot() { + super.testBitOpNot(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testBitOpNotMultipleSources() { + super.testBitOpNotMultipleSources(); + } + // Jredis returns null for rPush @Test public void testSort() { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java index 448959b9e..a507b5c26 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionIntegrationTests.java @@ -27,6 +27,7 @@ import org.junit.runner.RunWith; import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests; import org.springframework.data.redis.connection.DefaultStringRedisConnection; +import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.test.annotation.IfProfileValue; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -125,4 +126,12 @@ public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegra public void testSelect() { connection.select(1); } + + @Test(expected=UnsupportedOperationException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNotMultipleSources() { + connection.set("key1", "abcd"); + connection.set("key2", "efgh"); + actual.add(connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); + } } \ No newline at end of file diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java index 72757e92a..8e414d925 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.data.redis.SpinBarrier.waitFor; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -36,6 +37,7 @@ import org.springframework.data.redis.TestCondition; import org.springframework.data.redis.connection.AbstractConnectionPipelineIntegrationTests; import org.springframework.data.redis.connection.DefaultStringRedisConnection; import org.springframework.data.redis.connection.DefaultStringTuple; +import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; import org.springframework.test.annotation.IfProfileValue; import org.springframework.test.context.ContextConfiguration; @@ -337,6 +339,19 @@ public class LettuceConnectionPipelineIntegrationTests extends }, 1000l)); } + // LettuceConnection throws an UnsupportedOpException before we close the pipeline + @Test(expected=UnsupportedOperationException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNotMultipleSources() { + connection.set("key1", "abcd"); + connection.set("key2", "efgh"); + try { + actual.add(connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); + }finally { + getResults(); + } + } + @SuppressWarnings({ "rawtypes", "unchecked" }) protected Object convertResult(Object result) { Object convertedResult = super.convertResult(result); diff --git a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionIntegrationTests.java index 1d7ba24c6..1279035a1 100644 --- a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionIntegrationTests.java @@ -17,12 +17,10 @@ package org.springframework.data.redis.connection.srp; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.data.redis.RedisVersionUtils; import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests; import org.springframework.test.annotation.IfProfileValue; import org.springframework.test.context.ContextConfiguration; diff --git a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java index ad8ba4715..28027ae48 100644 --- a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java @@ -111,6 +111,14 @@ public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipel // as Exceptions } + @Ignore("https://github.com/spullara/redis-protocol/issues/24") + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testBitOpNotMultipleSources() { + // SRP issue exec does not report individual ErrorReplys in a MultiBulkReply + // as Exceptions + } + protected void initConnection() { connection.multi(); }