From ff60d0d2907fb5ba3fba2088b366f1a1cdef0c87 Mon Sep 17 00:00:00 2001 From: Jennifer Hickey Date: Sun, 16 Jun 2013 13:20:52 -0700 Subject: [PATCH] Add Redis 2.6 dump and restore commands to Connections DATAREDIS-182 --- .../DefaultStringRedisConnection.java | 32 +++++---- .../redis/connection/RedisKeyCommands.java | 4 ++ .../connection/jedis/JedisConnection.java | 8 +++ .../connection/jredis/JredisConnection.java | 8 +++ .../connection/lettuce/LettuceConnection.java | 24 +++++++ .../redis/connection/srp/SrpConnection.java | 24 +++++++ .../data/redis/SpinBarrier.java | 49 +++++++++++++ .../data/redis/TestCondition.java | 33 +++++++++ .../AbstractConnectionIntegrationTests.java | 70 +++++++++++++------ ...actConnectionPipelineIntegrationTests.java | 54 ++++++++++++++ .../JedisConnectionIntegrationTests.java | 25 +++++++ ...disConnectionPipelineIntegrationTests.java | 25 +++++++ .../JRedisConnectionIntegrationTests.java | 25 +++++++ .../LettuceConnectionIntegrationTests.java | 2 + ...uceConnectionPipelineIntegrationTests.java | 3 +- ...eConnectionPipelineTxIntegrationTests.java | 53 ++++++++++---- ...ConnectionTransactionIntegrationTests.java | 25 +++++++ ...ConnectionTransactionIntegrationTests.java | 21 +++++- 18 files changed, 437 insertions(+), 48 deletions(-) create mode 100644 src/test/java/org/springframework/data/redis/SpinBarrier.java create mode 100644 src/test/java/org/springframework/data/redis/TestCondition.java 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 0d609dd38..747193b98 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -584,6 +584,26 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return delegate.zUnionStore(destKey, sets); } + public Boolean pExpire(byte[] key, long millis) { + return delegate.pExpire(key, millis); + } + + public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + return delegate.pExpireAt(key, unixTimeInMillis); + } + + public Long pTtl(byte[] key) { + return delegate.pTtl(key); + } + + public byte[] dump(byte[] key) { + return delegate.dump(key); + } + + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + delegate.restore(key, ttlInMillis, serializedValue); + } + // // String methods // @@ -1167,18 +1187,6 @@ public class DefaultStringRedisConnection implements StringRedisConnection { return execute(command, serializeMulti(args)); } - public Boolean pExpire(byte[] key, long millis) { - return delegate.pExpire(key, millis); - } - - public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { - return delegate.pExpireAt(key, unixTimeInMillis); - } - - public Long pTtl(byte[] key) { - return delegate.pTtl(key); - } - public Boolean pExpire(String key, long millis) { return pExpire(serialize(key), millis); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java index bea97ceda..7e2c3d638 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java @@ -60,4 +60,8 @@ public interface RedisKeyCommands { List sort(byte[] key, SortParameters params); Long sort(byte[] key, SortParameters params, byte[] storeKey); + + byte[] dump(byte[] key); + + void restore(byte[] key, long ttlInMillis, byte[] serializedValue); } \ No newline at end of file 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 bae3833cd..474f98279 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 @@ -823,6 +823,14 @@ public class JedisConnection implements RedisConnection { throw new UnsupportedOperationException(); } + public byte[] dump(byte[] key) { + throw new UnsupportedOperationException(); + } + + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + throw new UnsupportedOperationException(); + } + public DataType type(byte[] key) { 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 cdcce83ad..de76e1da5 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 @@ -355,6 +355,14 @@ public class JredisConnection implements RedisConnection { throw new UnsupportedOperationException(); } + public byte[] dump(byte[] key) { + throw new UnsupportedOperationException(); + } + + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + throw new UnsupportedOperationException(); + } + public Set keys(byte[] pattern) { try { return new LinkedHashSet(jredis.keys(pattern)); 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 fbb76a1fa..b32356cd9 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 @@ -591,6 +591,30 @@ public class LettuceConnection implements RedisConnection { } } + public byte[] dump(byte[] key) { + try { + if (isPipelined()) { + pipeline(getAsyncConnection().dump(key)); + return null; + } + return getConnection().dump(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + try { + if (isPipelined()) { + pipeline(getAsyncConnection().restore(key, ttlInMillis, serializedValue)); + return; + } + getConnection().restore(key, ttlInMillis, serializedValue); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + public Set keys(byte[] pattern) { try { if (isPipelined()) { 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 8db282daa..00298a0d2 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 @@ -647,6 +647,30 @@ public class SrpConnection implements RedisConnection { } } + public byte[] dump(byte[] key) { + try { + if (isPipelined()) { + pipeline(pipeline.dump(key)); + return null; + } + return client.dump(key).data(); + } catch (Exception ex) { + throw convertSrpAccessException(ex); + } + } + + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + try { + if (isPipelined()) { + pipeline(pipeline.restore(key, ttlInMillis, serializedValue)); + return; + } + client.restore(key, ttlInMillis, serializedValue); + } catch (Exception ex) { + throw convertSrpAccessException(ex); + } + } + public DataType type(byte[] key) { try { if (isPipelined()) { diff --git a/src/test/java/org/springframework/data/redis/SpinBarrier.java b/src/test/java/org/springframework/data/redis/SpinBarrier.java new file mode 100644 index 000000000..2e44ba005 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/SpinBarrier.java @@ -0,0 +1,49 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis; + +/** + * + * @author Jennifer Hickey + * + */ +abstract public class SpinBarrier { + + /** + * Periodically tests for a condition until it is met or a timeout occurs + * + * @param condition + * The condition to periodically test + * @param timeout + * The timeout + * @return true if condition passes, false if condition does not pass within + * timeout + */ + public static boolean waitFor(TestCondition condition, long timeout) { + boolean passes = false; + for (long currentTime = System.currentTimeMillis(); System.currentTimeMillis() - currentTime < timeout;) { + if (condition.passes()) { + passes = true; + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + return passes; + } +} diff --git a/src/test/java/org/springframework/data/redis/TestCondition.java b/src/test/java/org/springframework/data/redis/TestCondition.java new file mode 100644 index 000000000..5a0c20b2a --- /dev/null +++ b/src/test/java/org/springframework/data/redis/TestCondition.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis; + +/** + * + * A condition to test periodically, used in conjunction with + * {@link SpinBarrier} + * + * @author Jennifer Hickey + * + */ +public interface TestCondition { + + /** + * + * @return true if condition passes + */ + boolean passes(); +} 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 4f9fb5185..5f8e4caf5 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.springframework.data.redis.SpinBarrier.waitFor; import java.util.ArrayList; import java.util.Arrays; @@ -44,7 +45,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.Address; import org.springframework.data.redis.Person; +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.RedisZSetCommands.Aggregate; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; @@ -562,6 +565,53 @@ public abstract class AbstractConnectionIntegrationTests { assertTrue(connection.pTtl("whatup") > -1); } + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testDumpAndRestore() { + connection.set("testing", "12"); + byte[] serializedResults = connection.dump("testing".getBytes()); + assertNotNull(serializedResults); + connection.del("testing"); + assertNull(connection.get("testing")); + connection.restore("testing".getBytes(), 0, serializedResults); + assertEquals("12",connection.get("testing")); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testDumpNonExistentKey() { + actual.add(connection.dump("fakey".getBytes())); + verifyResults(Arrays.asList(new Object[] { null }), actual); + } + + @Test(expected=RedisSystemException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreBadData() { + // Use something other than dump-specific serialization + connection.restore("testing".getBytes(), 0, "foo".getBytes()); + } + + @Test(expected=RedisSystemException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreExistingKey() { + connection.set("testing", "12"); + byte[] serializedResults = connection.dump("testing".getBytes()); + assertNotNull(serializedResults); + connection.restore("testing".getBytes(), 0, serializedResults); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreTtl() { + connection.set("testing", "12"); + byte[] serializedResults = connection.dump("testing".getBytes()); + assertNotNull(serializedResults); + connection.del("testing"); + assertNull(connection.get("testing")); + connection.restore("testing".getBytes(), 100l, serializedResults); + assertTrue(waitFor(new KeyExpired("testing"), 300l)); + } + @Test public void testType() { connection.set("something", "yo"); @@ -1257,26 +1307,6 @@ public abstract class AbstractConnectionIntegrationTests { assertEquals(expected, actual); } - protected boolean waitFor(TestCondition condition, long timeout) { - boolean passes = false; - for (long currentTime = System.currentTimeMillis(); System.currentTimeMillis() - - currentTime < timeout;) { - if (condition.passes()) { - passes = true; - break; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - } - return passes; - } - - protected interface TestCondition { - public boolean passes(); - } - protected class KeyExpired implements TestCondition { private String key; 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 242a45b28..9f4cc6799 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionPipelineIntegrationTests.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.springframework.data.redis.SpinBarrier.waitFor; import java.util.ArrayList; import java.util.Arrays; @@ -35,6 +37,7 @@ import java.util.UUID; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.springframework.data.redis.TestCondition; import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; @@ -160,6 +163,57 @@ abstract public class AbstractConnectionPipelineIntegrationTests extends }, 1000l)); } + @Test(expected=RedisPipelineException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreBadData() { + // Use something other than dump-specific serialization + connection.restore("testing".getBytes(), 0, "foo".getBytes()); + getResults(); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreExistingKey() { + connection.set("testing", "12"); + connection.dump("testing".getBytes()); + List results = getResults(); + initConnection(); + connection.restore("testing".getBytes(), 0, (byte[]) results.get(1)); + try { + getResults(); + fail("Expected pipeline exception restoring an existing key"); + }catch(RedisPipelineException e) { + } + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreTtl() { + connection.set("testing", "12"); + connection.dump("testing".getBytes()); + List results = getResults(); + initConnection(); + actual.add(connection.del("testing")); + actual.add(connection.get("testing")); + connection.restore("testing".getBytes(), 100l, (byte[]) results.get(results.size() - 1)); + verifyResults(Arrays.asList(new Object[] { 1l, null }), actual); + assertTrue(waitFor(new KeyExpired("testing"), 300l)); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testDumpAndRestore() { + connection.set("testing", "12"); + connection.dump("testing".getBytes()); + List results = getResults(); + initConnection(); + actual.add(connection.del("testing")); + actual.add((connection.get("testing"))); + connection.restore("testing".getBytes(), 0, (byte[]) results.get(results.size() - 1)); + actual.add(connection.get("testing")); + verifyResults(Arrays.asList(new Object[] { 1l, null, "12" }), actual); + } + @Test @IfProfileValue(name = "runLongTests", value = "true") public void testExpire() throws Exception { 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 304847384..0a6727774 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 @@ -80,6 +80,31 @@ public class JedisConnectionIntegrationTests extends AbstractConnectionIntegrati super.testPTtlNoExpire(); } + @Test(expected=UnsupportedOperationException.class) + public void testDumpAndRestore() { + super.testDumpAndRestore(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testDumpNonExistentKey() { + super.testDumpNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreBadData() { + super.testRestoreBadData(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreExistingKey() { + super.testRestoreExistingKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreTtl() { + super.testRestoreTtl(); + } + @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 957e5b8c7..70b592ec5 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 @@ -122,6 +122,31 @@ public class JedisConnectionPipelineIntegrationTests extends super.testPTtlNoExpire(); } + @Test(expected=UnsupportedOperationException.class) + public void testDumpAndRestore() { + super.testDumpAndRestore(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testDumpNonExistentKey() { + super.testDumpNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreBadData() { + super.testRestoreBadData(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreExistingKey() { + super.testRestoreExistingKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreTtl() { + super.testRestoreTtl(); + } + @Test(expected = RedisSystemException.class) public void testBitSet() throws Exception { super.testBitSet(); 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 5bdefa3cb..724b383a0 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 @@ -318,6 +318,31 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat super.testPTtlNoExpire(); } + @Test(expected=UnsupportedOperationException.class) + public void testDumpAndRestore() { + super.testDumpAndRestore(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testDumpNonExistentKey() { + super.testDumpNonExistentKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreBadData() { + super.testRestoreBadData(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreExistingKey() { + super.testRestoreExistingKey(); + } + + @Test(expected=UnsupportedOperationException.class) + public void testRestoreTtl() { + super.testRestoreTtl(); + } + // 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 601f8210c..448959b9e 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.test.annotation.IfProfileValue; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -42,6 +43,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegrationTests { @Test + @IfProfileValue(name = "runLongTests", value = "true") public void testMultiThreadsOneBlocking() throws Exception { Thread th = new Thread(new Runnable() { public void run() { 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 d33421362..72757e92a 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 @@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals; 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; @@ -32,6 +32,7 @@ import java.util.UUID; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +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; diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java index 3f5646cc5..eb35abc3e 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java @@ -1,14 +1,17 @@ package org.springframework.data.redis.connection.lettuce; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import java.util.ArrayList; import java.util.List; +import java.util.Properties; import org.junit.Test; import org.springframework.data.redis.connection.RedisPipelineException; +import org.springframework.test.annotation.IfProfileValue; /** * Integration test of {@link LettuceConnection} transactions within a pipeline @@ -30,8 +33,42 @@ public class LettuceConnectionPipelineTxIntegrationTests extends connection.set("dbparam", "foo"); assertNull(connection.dbSize()); List results = getResults(); - assertEquals(1, results.size()); - assertTrue((Long) results.get(0) > 0); + assertEquals(3, results.size()); + assertTrue((Long) results.get(2) > 0); + } + + @Test + public void testInfo() throws Exception { + assertNull(connection.info()); + List results = getResults(); + assertEquals(2, results.size()); + Properties info = LettuceUtils.info((String) results.get(1)); + assertTrue("at least 5 settings should be present", info.size() >= 5); + String version = info.getProperty("redis_version"); + assertNotNull(version); + } + + @Test(expected=RedisPipelineException.class) + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreBadData() { + // Use something other than dump-specific serialization + connection.restore("testing".getBytes(), 0, "foo".getBytes()); + getResults(); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreExistingKey() { + connection.set("testing", "12"); + connection.dump("testing".getBytes()); + List results = getResults(); + initConnection(); + connection.restore("testing".getBytes(), 0, (byte[]) results.get(2)); + try { + getResults(); + fail("Expected RedisPipelineException restoring existing key"); + }catch(RedisPipelineException e) { + } } protected void initConnection() { @@ -41,15 +78,7 @@ public class LettuceConnectionPipelineTxIntegrationTests extends protected List getResults() { assertNull(connection.exec()); - List results = new ArrayList(); - List pipelinedResults = connection.closePipeline(); - // filter out the return value of exec - for (Object result : pipelinedResults) { - if (!"OK".equals(result) && !("QUEUED").equals(result)) { - results.add(result); - } - } - return results; + return connection.closePipeline(); } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java index 16aabbcde..0c75559da 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionTransactionIntegrationTests.java @@ -16,15 +16,19 @@ package org.springframework.data.redis.connection.lettuce; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.List; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.test.annotation.IfProfileValue; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.lambdaworks.redis.RedisException; + /** * Integration test of {@link LettuceConnection} functionality within a * transaction @@ -93,6 +97,27 @@ public class LettuceConnectionTransactionIntegrationTests extends assertNull(getResults()); } + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreBadData() { + // Use something other than dump-specific serialization + connection.restore("testing".getBytes(), 0, "foo".getBytes()); + List results = getResults(); + assertTrue(results.get(0) instanceof RedisException); + } + + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreExistingKey() { + connection.set("testing", "12"); + connection.dump("testing".getBytes()); + List results = getResults(); + initConnection(); + connection.restore("testing".getBytes(), 0, (byte[]) results.get(1)); + List restoreResults = getResults(); + assertTrue(restoreResults.get(0) instanceof RedisException); + } + protected void initConnection() { connection.multi(); } 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 e986bb69e..ad8ba4715 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 @@ -29,8 +29,7 @@ import org.springframework.test.annotation.IfProfileValue; * @author Jennifer Hickey * */ -public class SrpConnectionTransactionIntegrationTests extends - SrpConnectionPipelineIntegrationTests { +public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipelineIntegrationTests { @Ignore public void testMultiDiscard() { @@ -87,7 +86,7 @@ public class SrpConnectionTransactionIntegrationTests extends } @Test - @IfProfileValue(name = "redisVersion", values = {"2.4", "2.6"}) + @IfProfileValue(name = "redisVersion", values = { "2.4", "2.6" }) public void testGetRangeSetRange() { connection.set("rangekey", "supercalifrag"); actual.add(connection.getRange("rangekey", 0l, 2l)); @@ -96,6 +95,22 @@ public class SrpConnectionTransactionIntegrationTests extends verifyResults(Arrays.asList(new Object[] { "sup", 13l, "suckrcalifrag" }), actual); } + @Ignore("https://github.com/spullara/redis-protocol/issues/24") + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreBadData() { + // SRP issue exec does not report individual ErrorReplys in a MultiBulkReply + // as Exceptions + } + + @Ignore("https://github.com/spullara/redis-protocol/issues/24") + @Test + @IfProfileValue(name = "redisVersion", value = "2.6") + public void testRestoreExistingKey() { + // SRP issue exec does not report individual ErrorReplys in a MultiBulkReply + // as Exceptions + } + protected void initConnection() { connection.multi(); }