Validate converted pipeline results in conn tests

DATAREDIS-200
This commit is contained in:
Jennifer Hickey
2013-07-17 11:25:39 -07:00
parent dd8b0561ea
commit 6d21cda407
19 changed files with 2298 additions and 2504 deletions

View File

@@ -0,0 +1,456 @@
package org.springframework.data.redis.connection;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.test.annotation.IfProfileValue;
abstract public class AbstractConnectionTransactionIntegrationTests extends
AbstractConnectionIntegrationTests {
protected boolean convert = true;
protected boolean convertLongToBoolean = true;
protected boolean convertStringToProps = false;
@Ignore
public void testMultiDiscard() {
}
@Ignore
public void testMultiExec() {
}
@Ignore
public void testUnwatch() {
}
@Ignore
public void testWatch() {
}
/*
* Using blocking ops inside a tx does not make a lot of sense as it would require blocking the
* entire server in order to execute the block atomically, which in turn does not allow other
* clients to perform a push operation. *
*/
@Ignore
public void testBLPop() {
}
@Ignore
public void testBRPop() {
}
@Ignore
public void testBRPopLPush() {
}
@Ignore
public void testBLPopTimeout() {
}
@Ignore
public void testBRPopTimeout() {
}
@Ignore
public void testBRPopLPushTimeout() {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithNamedChannels() throws Exception {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithPatterns() throws Exception {
}
@Ignore
public void testNullKey() throws Exception {
}
@Ignore
public void testNullValue() throws Exception {
}
@Ignore
public void testHashNullKey() throws Exception {
}
@Ignore
public void testHashNullValue() throws Exception {
}
// Type conversion overrides
@Test
public void testExecute() {
connection.set("foo", "bar");
actual.add(connection.execute("GET", "foo"));
assertEquals("bar", getResults().get(0));
}
@Test
public void testExecuteNoArgs() {
actual.add(connection.execute("PING"));
assertEquals("PONG", getResults().get(0));
}
@Test
public void testSort() {
convertLongToBoolean = false;
super.testSort();
}
@Test
public void testSortStore() {
convertLongToBoolean = false;
super.testSortStore();
}
@Test
public void testSortNullParams() {
convertLongToBoolean = false;
super.testSortNullParams();
}
@Test
public void testDbSize() {
convertLongToBoolean = false;
super.testDbSize();
}
@Test
public void testFlushDb() {
convertLongToBoolean = false;
super.testFlushDb();
}
@Test
public void testDel() {
convertLongToBoolean = false;
super.testDel();
}
@Test
public void testIncDecrByLong() {
convertLongToBoolean = false;
super.testIncrDecrByLong();
}
@Test
public void testDecrByIncrBy() {
convertLongToBoolean = false;
super.testDecrByIncrBy();
}
@Test
public void testIncrDecr() {
convertLongToBoolean = false;
super.testIncDecr();
}
@Test
public void testLInsert() {
convertLongToBoolean = false;
super.testLInsert();
}
@Test
public void testLRem() {
convertLongToBoolean = false;
super.testLRem();
}
@Test
public void testLPop() {
convertLongToBoolean = false;
super.testLPop();
}
@Test
public void testLLen() {
convertLongToBoolean = false;
super.testLLen();
}
@Test
public void testLSet() {
convertLongToBoolean = false;
super.testLSet();
}
@Test
public void testLTrim() {
convertLongToBoolean = false;
super.testLTrim();
}
@Test
public void testRPop() {
convertLongToBoolean = false;
super.testRPop();
}
@Test
public void testRPopLPush() {
convertLongToBoolean = false;
super.testRPopLPush();
}
@Test
public void testLPushX() {
convertLongToBoolean = false;
super.testLPushX();
}
@Test
public void testRPushX() {
convertLongToBoolean = false;
super.testRPushX();
}
@Test
public void testLIndex() {
convertLongToBoolean = false;
super.testLIndex();
}
@Test
public void testLPush() throws Exception {
convertLongToBoolean = false;
super.testLPush();
}
@Test
public void testSDiffStore() {
convertLongToBoolean = false;
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sDiffStore("thirdset", "myset", "otherset"));
actual.add(connection.sMembers("thirdset"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 1l,
new HashSet<String>(Collections.singletonList("foo")) }));
}
@Test
public void testSInterStore() {
convertLongToBoolean = false;
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sInterStore("thirdset", "myset", "otherset"));
actual.add(connection.sMembers("thirdset"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 1l,
new HashSet<String>(Collections.singletonList("bar")) }));
}
@Test
public void testZRank() {
convertLongToBoolean = false;
actual.add(connection.zAdd("myset", 2, "Bob"));
actual.add(connection.zAdd("myset", 1, "James"));
actual.add(connection.zRank("myset", "James"));
actual.add(connection.zRank("myset", "Bob"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 0l, 1l }));
}
@Test
public void testZRemRangeByScore() {
convertLongToBoolean = false;
actual.add(connection.zAdd("myset", 2, "Bob"));
actual.add(connection.zAdd("myset", 1, "James"));
actual.add(connection.zRemRangeByScore("myset", 0d, 1d));
actual.add(connection.zRange("myset", 0l, -1l));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l,
new LinkedHashSet<String>(Arrays.asList(new String[] { "Bob" })) }));
}
@Test
public void testZRevRank() {
convertLongToBoolean = false;
actual.add(connection.zAdd("myset", 2, "Bob"));
actual.add(connection.zAdd("myset", 1, "James"));
actual.add(connection.zAdd("myset", 3, "Joe"));
actual.add(connection.zRevRank("myset", "Joe"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 0l }));
}
@Test
public void testIncrDecrByLong() {
convertLongToBoolean = false;
super.testIncrDecrByLong();
}
@Test
public void testIncDecr() {
convertLongToBoolean = false;
super.testIncDecr();
}
@Test
public void testType() {
connection.set("something", "yo");
actual.add(connection.type("something"));
verifyResults(Arrays.asList(new Object[] { "string" }));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testBitCountNonExistentKey() {
convertLongToBoolean = false;
super.testBitCountNonExistentKey();
}
@Test
public void testInfo() throws Exception {
convertStringToProps = true;
super.testInfo();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testInfoBySection() throws Exception {
convertStringToProps = true;
super.testInfoBySection();
}
@Test
public void testDumpAndRestore() {
convert = false;
super.testDumpAndRestore();
}
@Test
public void testScriptLoadEvalSha() {
convert = false;
super.testScriptLoadEvalSha();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaArrayStrings() {
convert = false;
super.testEvalShaArrayStrings();
}
@Test(expected = RedisSystemException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreExistingKey() {
convert = false;
super.testRestoreExistingKey();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnString() {
convert = false;
super.testEvalReturnString();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayStrings() {
convert = false;
super.testEvalReturnArrayStrings();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreTtl() {
convert = false;
super.testRestoreTtl();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptKill() {
// Impossible to call script kill in a tx because you can't issue the
// exec command while Redis is running a script
connection.scriptKill();
}
protected void initConnection() {
connection.multi();
}
protected abstract DataAccessException convertException(Exception ex);
protected List<Object> getResults() {
List<Object> actual = connection.exec();
if (actual == null) {
return null;
}
List<Object> serializedResults = new ArrayList<Object>();
for (Object result : actual) {
Object convertedResult = convertResult(result);
if (convertedResult instanceof Exception) {
throw convertException((Exception) convertedResult);
}
if (!"OK".equals(convertedResult) && !"QUEUED".equals(convertedResult)) {
serializedResults.add(convertedResult);
}
}
return serializedResults;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
if (!convert) {
return result;
}
if (result instanceof List && !(((List) result).isEmpty())
&& ((List) result).get(0) instanceof byte[]) {
return (SerializationUtils.deserialize((List<byte[]>) result, stringSerializer));
} else if (result instanceof byte[]) {
return (stringSerializer.deserialize((byte[]) result));
} else if (result instanceof Map
&& ((Map) result).keySet().iterator().next() instanceof byte[]) {
return (SerializationUtils.deserialize((Map) result, stringSerializer));
} else if (result instanceof Set && !(((Set) result).isEmpty())) {
Object firstResult = ((Set) result).iterator().next();
if (firstResult instanceof byte[]) {
return (SerializationUtils.deserialize((Set) result, stringSerializer));
}
} else if (convertLongToBoolean && result instanceof Long) {
if ((Long) result == 1l) {
return true;
} else if ((Long) result == 0l) {
return false;
} else {
return result;
}
} else if (convertStringToProps && result instanceof String) {
return Converters.toProperties((String) result);
}
return result;
}
protected void verifyResults(List<Object> expected) {
List<Object> expectedTx = new ArrayList<Object>();
for (int i = 0; i < actual.size(); i++) {
expectedTx.add(null);
}
assertEquals(expectedTx, actual);
List<Object> results = getResults();
assertEquals(expected, results);
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.data.redis.connection.jedis;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -182,32 +180,6 @@ public class JedisConnectionIntegrationTests extends AbstractConnectionIntegrati
super.testInfoBySection();
}
@Test
public void testIncrDecrByLong() {
String key = "test.count";
long largeNumber = 0x123456789L; // > 32bits
connection.set(key, "0");
connection.incrBy(key, largeNumber);
assertEquals(largeNumber, Long.valueOf(connection.get(key)).longValue());
connection.decrBy(key, largeNumber);
assertEquals(0, Long.valueOf(connection.get(key)).longValue());
connection.decrBy(key, 2 * largeNumber);
assertEquals(-2 * largeNumber, Long.valueOf(connection.get(key)).longValue());
}
@Test
public void testHashIncrDecrByLong() {
String key = "test.hcount";
String hkey = "hashkey";
long largeNumber = 0x123456789L; // > 32bits
connection.hSet(key, hkey, "0");
connection.hIncrBy(key, hkey, largeNumber);
assertEquals(largeNumber, Long.valueOf(connection.hGet(key, hkey)).longValue());
connection.hIncrBy(key, hkey, -2 * largeNumber);
assertEquals(-largeNumber, Long.valueOf(connection.hGet(key, hkey)).longValue());
}
@Test
public void testCreateConnectionWithDb() {
JedisConnectionFactory factory2 = new JedisConnectionFactory();

View File

@@ -15,27 +15,15 @@
*/
package org.springframework.data.redis.connection.jedis;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.redis.connection.AbstractConnectionPipelineIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringTuple;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import redis.clients.jedis.Tuple;
/**
* Integration test of {@link JedisConnection} pipeline functionality
*
@@ -47,12 +35,6 @@ import redis.clients.jedis.Tuple;
public class JedisConnectionPipelineIntegrationTests extends
AbstractConnectionPipelineIntegrationTests {
/**
* Individual results from closePipeline should be converted from
* LinkedHashSet to List
**/
private boolean convertResultToList;
@After
public void tearDown() {
try {
@@ -67,19 +49,19 @@ public class JedisConnectionPipelineIntegrationTests extends
connection = null;
}
@Ignore("DATAREDIS-143 Jedis ClassCastExceptions closing pipeline on certain ops")
@Ignore("DATAREDIS-143 Pipeline tries to return String instead of List<String>")
public void testGetConfig() {
}
@Ignore("DATAREDIS-143 Jedis ClassCastExceptions closing pipeline on certain ops")
@Ignore("DATAREDIS-143 MultiResponseBuilder trying to cast QUEUED to a List")
public void testWatch() {
}
@Ignore("DATAREDIS-143 Jedis ClassCastExceptions closing pipeline on certain ops")
@Ignore("DATAREDIS-143 MultiResponseBuilder trying to cast QUEUED to a List")
public void testUnwatch() {
}
@Ignore("DATAREDIS-143 Jedis ClassCastExceptions closing pipeline on certain ops")
@Ignore("DATAREDIS-143 Pipeline tries to return List<String> instead of Long on sort")
public void testSortStore() {
}
@@ -162,7 +144,7 @@ public class JedisConnectionPipelineIntegrationTests extends
@Test(expected = UnsupportedOperationException.class)
public void testBitGet() {
connection.getBit("foo", 1l);
connection.getBit("bitly", 1l);
}
@Test(expected=UnsupportedOperationException.class)
@@ -359,7 +341,7 @@ public class JedisConnectionPipelineIntegrationTests extends
@Test(expected=UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptFlush() {
super.testScriptFlush();
connection.scriptFlush();
}
@Test(expected=UnsupportedOperationException.class)
@@ -385,129 +367,4 @@ public class JedisConnectionPipelineIntegrationTests extends
public void testInfoBySection() throws Exception {
super.testInfoBySection();
}
// Overrides, usually due to return values being Long vs Boolean or Set vs
// List
@Test
public void testRenameNx() {
connection.set("nxtest", "testit");
actual.add(connection.renameNX("nxtest", "newnxtest"));
actual.add(connection.get("newnxtest"));
actual.add(connection.exists("nxtest"));
verifyResults(Arrays.asList(new Object[] { 1l, "testit", false }), actual);
}
@Test
public void testKeys() throws Exception {
convertResultToList = true;
super.testKeys();
}
@Test
public void testZAddAndZRange() {
convertResultToList = true;
super.testZAddAndZRange();
}
@Test
public void testZIncrBy() {
convertResultToList = true;
super.testZIncrBy();
}
@Test
public void testZInterStore() {
convertResultToList = true;
super.testZInterStore();
}
@Test
public void testZRangeByScore() {
convertResultToList = true;
super.testZRangeByScore();
}
@Test
public void testZRangeByScoreOffsetCount() {
convertResultToList = true;
super.testZRangeByScoreOffsetCount();
}
@Test
public void testZRevRange() {
convertResultToList = true;
super.testZRevRange();
}
@Test
public void testZRem() {
convertResultToList = true;
super.testZRem();
}
@Test
public void testZRemRangeByScore() {
convertResultToList = true;
super.testZRemRangeByScore();
}
@Test
public void testZUnionStore() {
convertResultToList = true;
super.testZUnionStore();
}
@Test
public void testZRemRangeByRank() {
convertResultToList = true;
super.testZRemRangeByRank();
}
@Test
public void testHDel() throws Exception {
actual.add(connection.hSet("test", "key", "val"));
actual.add(connection.hDel("test", "key"));
actual.add(connection.hDel("test", "foo"));
actual.add(connection.hExists("test", "key"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 0l, false }), actual);
}
@Test
public void testHSetGet() throws Exception {
String hash = getClass() + ":hashtest";
String key1 = UUID.randomUUID().toString();
String key2 = UUID.randomUUID().toString();
String value1 = "foo";
String value2 = "bar";
actual.add(connection.hSet(hash, key1, value1));
actual.add(connection.hSet(hash, key2, value2));
actual.add(connection.hGet(hash, key1));
actual.add(connection.hGetAll(hash));
Map<String, String> expected = new HashMap<String, String>();
expected.put(key1, value1);
expected.put(key2, value2);
verifyResults(Arrays.asList(new Object[] { 1l, 1l, value1, expected }), actual);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
Object convertedResult = super.convertResult(result);
if (convertedResult instanceof Set) {
if (convertResultToList) {
// Other providers represent zSets as Lists, so transform here
return new ArrayList((Set) convertedResult);
} else if (!(((Set) convertedResult).isEmpty())
&& ((Set) convertedResult).iterator().next() instanceof Tuple) {
List<StringTuple> tuples = new ArrayList<StringTuple>();
for (Tuple value : ((Set<Tuple>) convertedResult)) {
DefaultStringTuple tuple = new DefaultStringTuple(
(byte[]) value.getBinaryElement(), value.getElement(), value.getScore());
tuples.add(tuple);
}
return tuples;
}
}
return convertedResult;
}
}

View File

@@ -18,12 +18,24 @@ package org.springframework.data.redis.connection.jedis;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.RedisVersionUtils;
import org.springframework.data.redis.connection.AbstractConnectionTransactionIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringTuple;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import redis.clients.jedis.Tuple;
/**
* Integration test of {@link JedisConnection} transaction functionality.
@@ -35,61 +47,309 @@ import org.springframework.data.redis.RedisVersionUtils;
* @author Jennifer Hickey
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("JedisConnectionIntegrationTests-context.xml")
public class JedisConnectionTransactionIntegrationTests extends
JedisConnectionPipelineIntegrationTests {
AbstractConnectionTransactionIntegrationTests {
@Ignore
public void testMultiDiscard() {
@After
public void tearDown() {
try {
connection.flushDb();
connection.close();
} catch (Exception e) {
// Jedis leaves some incomplete data in OutputStream on NPE caused
// by null key/value tests
// Attempting to close the connection will result in error on
// sending QUIT to Redis
}
connection = null;
}
@Ignore
public void testMultiExec() {
@Ignore("DATAREDIS-143 transaction tries to return List<String> instead of Long on sort")
public void testSortStore() {
}
@Ignore
public void testUnwatch() {
}
@Ignore
public void testWatch() {
}
/*
* Using blocking ops inside a tx does not make a lot of sense as it would
* require blocking the entire server in order to execute the block
* atomically, which in turn does not allow other clients to perform a push
* operation. *
*/
@Ignore
public void testBLPop() {
}
@Ignore
public void testBRPop() {
}
@Ignore
public void testBRPopLPush() {
}
@Ignore
public void testBLPopTimeout() {
}
@Ignore
public void testBRPopTimeout() {
}
@Ignore
public void testBRPopLPushTimeout() {
}
@Ignore
public void testOpenPipelineTwice() {
@Ignore("DATAREDIS-143 transaction tries to return Long instead of List<String> on sort with no params")
public void testSortStoreNullParams() {
}
// Unsupported Ops
@Test(expected = UnsupportedOperationException.class)
public void testPExpire() {
super.testPExpire();
}
@Test(expected = UnsupportedOperationException.class)
public void testPExpireKeyNotExists() {
super.testPExpireKeyNotExists();
}
@Test(expected = UnsupportedOperationException.class)
public void testPExpireAt() {
super.testPExpireAt();
}
@Test(expected = UnsupportedOperationException.class)
public void testPExpireAtKeyNotExists() {
super.testPExpireAtKeyNotExists();
}
@Test(expected = UnsupportedOperationException.class)
public void testPTtl() {
super.testPTtl();
}
@Test(expected = UnsupportedOperationException.class)
public void testPTtlNoExpire() {
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 = UnsupportedOperationException.class)
public void testBitSet() throws Exception {
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 = UnsupportedOperationException.class)
public void testRandomKey() {
super.testRandomKey();
}
@Test(expected = UnsupportedOperationException.class)
public void testGetRangeSetRange() {
super.testGetRangeSetRange();
}
@Test(expected = UnsupportedOperationException.class)
public void testPingPong() throws Exception {
super.testPingPong();
}
@Test(expected = UnsupportedOperationException.class)
public void testInfo() throws Exception {
super.testInfo();
}
@Test(expected = UnsupportedOperationException.class)
public void testZRevRangeByScore() {
super.testZRevRangeByScore();
}
@Test(expected = UnsupportedOperationException.class)
public void testZRevRangeByScoreOffsetCount() {
super.testZRevRangeByScoreOffsetCount();
}
@Test(expected = UnsupportedOperationException.class)
public void testZRevRangeByScoreWithScores() {
super.testZRevRangeByScoreWithScores();
}
@Test(expected = UnsupportedOperationException.class)
public void testZRevRangeByScoreWithScoresOffsetCount() {
super.testZRevRangeByScoreWithScoresOffsetCount();
}
@Test(expected = UnsupportedOperationException.class)
public void testHIncrByDouble() {
super.testHIncrByDouble();
}
@Test(expected = UnsupportedOperationException.class)
public void testIncrByDouble() {
super.testIncrByDouble();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptLoadEvalSha() {
super.testScriptLoadEvalSha();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaArrayStrings() {
super.testEvalShaArrayStrings();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaNotFound() {
super.testEvalShaNotFound();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnString() {
super.testEvalReturnString();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnNumber() {
super.testEvalReturnNumber();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleOK() {
super.testEvalReturnSingleOK();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleError() {
super.testEvalReturnSingleError();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnFalse() {
super.testEvalReturnFalse();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnTrue() {
super.testEvalReturnTrue();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayStrings() {
super.testEvalReturnArrayStrings();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayNumbers() {
super.testEvalReturnArrayNumbers();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayOKs() {
super.testEvalReturnArrayOKs();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayFalses() {
super.testEvalReturnArrayFalses();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayTrues() {
super.testEvalReturnArrayTrues();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptExists() {
super.testScriptExists();
}
@IfProfileValue(name = "redisVersion", value = "2.6")
@Test(expected = UnsupportedOperationException.class)
public void testScriptKill() {
connection.scriptKill();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptFlush() {
connection.scriptFlush();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testSRandMemberCount() {
super.testSRandMemberCount();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testSRandMemberCountKeyNotExists() {
super.testSRandMemberCountKeyNotExists();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testSRandMemberCountNegative() {
super.testSRandMemberCountNegative();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testInfoBySection() throws Exception {
super.testInfoBySection();
}
@Test(expected = UnsupportedOperationException.class)
public void testGetConfig() {
@@ -107,19 +367,34 @@ public class JedisConnectionTransactionIntegrationTests extends
try {
// Syntax error on queued commands are swallowed and no results are
// returned
verifyResults(Arrays.asList(new Object[] {}), actual);
if(RedisVersionUtils.atLeast("2.6.5", connection)) {
verifyResults(Arrays.asList(new Object[] {}));
if (RedisVersionUtils.atLeast("2.6.5", connection)) {
fail("Redis 2.6 should throw an Exception on exec if commands are invalid");
}
}catch(InvalidDataAccessApiUsageException e) {
} catch (InvalidDataAccessApiUsageException e) {
}
}
protected void initConnection() {
connection.multi();
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
Object convertedResult = super.convertResult(result);
if (convertedResult instanceof Set) {
if (!(((Set) convertedResult).isEmpty())
&& ((Set) convertedResult).iterator().next() instanceof Tuple) {
Set<StringTuple> tuples = new LinkedHashSet<StringTuple>();
for (Tuple value : ((Set<Tuple>) convertedResult)) {
DefaultStringTuple tuple = new DefaultStringTuple(
(byte[]) value.getBinaryElement(), value.getElement(), value.getScore());
tuples.add(tuple);
}
return tuples;
}
}
return convertedResult;
}
protected List<Object> getResults() {
return connection.exec();
@Override
protected DataAccessException convertException(Exception ex) {
return JedisConverters.toDataAccessException(ex);
}
}

View File

@@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import org.apache.commons.pool.impl.GenericObjectPool.Config;
import org.jredis.JRedis;
@@ -86,6 +88,10 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
public void testMSetNxFailure() {
}
@Ignore("JRedis casts to int")
public void testIncrDecrByLong() {
}
@Ignore("Ping returns status response instead of value response")
public void testExecuteNoArgs() {
}
@@ -409,6 +415,11 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
super.testHIncrByDouble();
}
@Test(expected=UnsupportedOperationException.class)
public void testHashIncrDecrByLong() {
super.testHashIncrDecrByLong();
}
@Test(expected=UnsupportedOperationException.class)
public void testIncrByDouble() {
super.testIncrByDouble();
@@ -539,7 +550,17 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
super.testInfoBySection();
}
// Jredis returns null for rPush
// Jredis returns null for rPush and lPush
@Test
public void testLLen() {
connection.rPush("PopList", "hello");
connection.rPush("PopList", "big");
connection.rPush("PopList", "world");
connection.rPush("PopList", "hello");
actual.add(connection.lLen("PopList"));
verifyResults(Arrays.asList(new Object[] { 4l }));
}
@Test
public void testSort() {
connection.rPush("sortlist", "foo");
@@ -565,8 +586,7 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
connection.rPush("sortlist", "2");
connection.rPush("sortlist", "3");
actual.add(connection.sort("sortlist", null));
verifyResults(
Arrays.asList(new Object[] { Arrays.asList(new String[] { "2", "3", "5" }) }), actual);
verifyResults(Arrays.asList(new Object[] { Arrays.asList(new String[] { "2", "3", "5" }) }));
}
@Test
@@ -576,8 +596,7 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
connection.rPush("sortlist", "5");
actual.add(connection.sort("sortlist", null, "newlist"));
actual.add(connection.lRange("newlist", 0, 9));
verifyResults(Arrays.asList(new Object[] { 3l,
Arrays.asList(new String[] { "3", "5", "9" }) }), actual);
verifyResults(Arrays.asList(new Object[] { 3l, Arrays.asList(new String[] { "3", "5", "9" }) }));
}
@Test
@@ -646,16 +665,6 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
assertEquals(Arrays.asList(new String[] { "baz", "bar" }), connection.lRange("testlist", 0, -1));
}
@Test
public void testLLen() {
connection.rPush("PopList", "hello");
connection.rPush("PopList", "big");
connection.rPush("PopList", "world");
connection.rPush("PopList", "hello");
actual.add(connection.lLen("PopList"));
verifyResults(Arrays.asList(new Object[] { 4l }), actual);
}
@Test
public void testExecute() {
connection.set("foo", "bar");
@@ -663,11 +672,48 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
assertEquals("bar", stringSerializer.deserialize(response.getBulkData()));
}
@Test
public void testSDiffStore() {
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sDiffStore("thirdset", "myset", "otherset"));
actual.add(connection.sMembers("thirdset"));
// JRedis returns void for sDiffStore, so we always return -1
verifyResults(Arrays.asList(new Object[] { true, true, true, -1l,
new HashSet<String>(Collections.singletonList("foo")) }));
}
@Test
public void testSInterStore() {
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sInterStore("thirdset", "myset", "otherset"));
actual.add(connection.sMembers("thirdset"));
// JRedis returns void for sInterStore, so we always return -1
verifyResults(Arrays.asList(new Object[] { true, true, true, -1l,
new HashSet<String>(Collections.singletonList("bar")) }));
}
@Test
public void testSUnionStore() {
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sAdd("otherset", "baz"));
actual.add(connection.sUnionStore("thirdset", "myset", "otherset"));
actual.add(connection.sMembers("thirdset"));
// JRedis returns void for sUnionStore, so we always return -1
verifyResults(Arrays.asList(new Object[] { true, true, true, true, -1l,
new HashSet<String>(Arrays.asList(new String[] { "foo", "bar", "baz" })) }));
}
@Test
public void testMove() {
connection.set("foo", "bar");
actual.add(connection.move("foo", 1));
verifyResults(Arrays.asList(new Object[] { true}), actual);
verifyResults(Arrays.asList(new Object[] { true}));
// JRedis does not support select() on existing conn, create new one
JredisConnectionFactory factory2 = new JredisConnectionFactory();
factory2.setDatabase(1);

View File

@@ -56,7 +56,7 @@ public class AuthenticatingRedisClientTests {
@Test
public void codecConnect() {
RedisConnection<byte[], byte[]> conn = client.connect(LettuceUtils.CODEC);
RedisConnection<byte[], byte[]> conn = client.connect(LettuceConnection.CODEC);
conn.ping();
}
@@ -68,7 +68,7 @@ public class AuthenticatingRedisClientTests {
@Test
public void codecConnectAsync() {
RedisAsyncConnection<byte[], byte[]> conn = client.connectAsync(LettuceUtils.CODEC);
RedisAsyncConnection<byte[], byte[]> conn = client.connectAsync(LettuceConnection.CODEC);
conn.ping();
}
@@ -80,7 +80,7 @@ public class AuthenticatingRedisClientTests {
@Test
public void codecConnectPubSub() {
RedisPubSubConnection<byte[], byte[]> conn = client.connectPubSub(LettuceUtils.CODEC);
RedisPubSubConnection<byte[], byte[]> conn = client.connectPubSub(LettuceConnection.CODEC);
conn.ping();
}

View File

@@ -201,11 +201,6 @@ public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegra
factory2.destroy();
}
@Test(expected = UnsupportedOperationException.class)
public void testSelect() {
super.testSelect();
}
@Test
public void testSelectNotShared() {
DefaultLettucePool pool = new DefaultLettucePool(SettingsUtils.getHost(),
@@ -219,6 +214,11 @@ public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegra
factory2.destroy();
}
@Test(expected = UnsupportedOperationException.class)
public void testSelect() {
super.testSelect();
}
@Test(expected=UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testBitOpNotMultipleSources() {
@@ -241,6 +241,7 @@ public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegra
final AtomicBoolean scriptDead = new AtomicBoolean(false);
Thread th = new Thread(new Runnable() {
public void run() {
// Use a different factory to get a non-shared native conn for blocking script
final LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(),
SettingsUtils.getPort());
factory2.afterPropertiesSet();
@@ -268,7 +269,7 @@ public class LettuceConnectionIntegrationTests extends AbstractConnectionIntegra
public void testMove() {
connection.set("foo", "bar");
actual.add(connection.move("foo", 1));
verifyResults(Arrays.asList(new Object[] { true}), actual);
verifyResults(Arrays.asList(new Object[] { true}));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
factory2.setDatabase(1);

View File

@@ -16,20 +16,12 @@
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.Assume.assumeTrue;
import static org.springframework.data.redis.SpinBarrier.waitFor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Ignore;
@@ -41,18 +33,13 @@ import org.springframework.data.redis.SettingsUtils;
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.ReturnType;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.lambdaworks.redis.KeyValue;
import com.lambdaworks.redis.ScoredValue;
/**
* Integration test of {@link LettuceConnection} pipeline functionality
*
@@ -73,308 +60,6 @@ public class LettuceConnectionPipelineIntegrationTests extends
super.testSelect();
}
// Overrides, usually due to return values being Long vs Boolean or Set vs
// List
@Test
public void testWatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
//Give some time for watch to be asynch executed
Thread.sleep(500);
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
conn2.close();
connection.multi();
connection.set("testitnow", "somethingelse");
actual.add(connection.exec());
actual.add(connection.get("testitnow"));
verifyResults(Arrays.asList(new Object[] { null, "something" }), actual);
}
@Test
public void testUnwatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
connection.unwatch();
connection.multi();
//Give some time for unwatch to be asynch executed
Thread.sleep(500);
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
connection.set("testitnow", "somethingelse");
connection.get("testitnow");
connection.exec();
List<Object> convertedResults = convertResults();
assertEquals(Arrays.asList(new Object[] {"somethingelse"}), convertedResults);
}
@Test
public void testBLPop() {
// Use a different synchronous connection to add items to the list, else blpop may
// execute before items in the list (LettuceConnection uses different underlying conns for blocking ops)
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.lPush("poplist", "foo");
conn2.lPush("poplist", "bar");
actual.add(connection.bLPop(1, "poplist", "otherlist"));
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new String[] {"poplist", "bar"})}), actual);
}
@Test
public void testBRPop() {
// Use a different synchronous connection to add items to the list, else blpop may
// execute before items in the list (LettuceConnection uses different underlying conns for blocking ops)
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.rPush("rpoplist", "bar");
conn2.rPush("rpoplist", "foo");
actual.add(connection.bRPop(1, "rpoplist"));
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new String[] {"rpoplist", "foo"})}), actual);
}
@Test
public void testBRPopLPush() {
// Use a different synchronous connection to add items to the list, else blpop may
// execute before items in the list (LettuceConnection uses different underlying conns for blocking ops)
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.rPush("PopList", "hello");
conn2.rPush("PopList", "world");
conn2.rPush("pop2", "hey");
assertNull(connection.bRPopLPush(1, "PopList", "pop2"));
List<Object> results = convertResults();
assertEquals(Arrays.asList(new String[] { "world" }), results);
assertEquals(Arrays.asList(new String[] { "hello" }), connection.lRange("PopList", 0, -1));
assertEquals(Arrays.asList(new String[] { "world", "hey" }),
connection.lRange("pop2", 0, -1));
}
@Test
public void testHSetGet() throws Exception {
String hash = getClass() + ":hashtest";
String key1 = UUID.randomUUID().toString();
String key2 = UUID.randomUUID().toString();
String value1 = "foo";
String value2 = "bar";
actual.add(connection.hSet(hash, key1, value1));
actual.add(connection.hSet(hash, key2, value2));
actual.add(connection.hGet(hash, key1));
actual.add(connection.hGetAll(hash));
Map<String, String> expected = new HashMap<String, String>();
expected.put(key1, value1);
expected.put(key2, value2);
verifyResults(Arrays.asList(new Object[] { true, true, value1, expected }), actual);
}
@Test
public void testInfo() throws Exception {
assertNull(connection.info());
List<Object> results = getResults();
assertEquals(1, results.size());
Properties info = LettuceUtils.info((String) results.get(0));
assertTrue("at least 5 settings should be present", info.size() >= 5);
String version = info.getProperty("redis_version");
assertNotNull(version);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testInfoBySection() throws Exception {
assertNull(connection.info("server"));
List<Object> results = getResults();
assertEquals(1, results.size());
Properties info = LettuceUtils.info((String) results.get(0));
assertTrue("at least 5 settings should be present", info.size() >= 5);
String version = info.getProperty("redis_version");
assertNotNull(version);
}
@Test
public void testMSetNx() {
Map<String, String> vals = new HashMap<String, String>();
vals.put("height", "5");
vals.put("width", "1");
connection.mSetNXString(vals);
assertNull(connection.mGet("height", "width"));
verifyResults(
Arrays.asList(new Object[] { true, Arrays.asList(new String[] { "5", "1" }) }),
actual);
}
@Test
public void testMSetNxFailure() {
connection.set("height", "2");
Map<String, String> vals = new HashMap<String, String>();
vals.put("height", "5");
vals.put("width", "1");
actual.add(connection.mSetNXString(vals));
actual.add(connection.mGet("height", "width"));
verifyResults(Arrays.asList(new Object[] { false, Arrays.asList(new String[] { "2", null }) }),
actual);
}
@Test
public void testSetNx() {
actual.add(connection.setNX("notaround", "54"));
actual.add(connection.get("notaround"));
actual.add(connection.setNX("notaround", "55"));
actual.add(connection.get("notaround"));
verifyResults(Arrays.asList(new Object[] { true, "54", false, "54" }), actual);
}
@Test
public void testRenameNx() {
connection.set("nxtest", "testit");
actual.add(connection.renameNX("nxtest", "newnxtest"));
actual.add(connection.get("newnxtest"));
actual.add(connection.exists("nxtest"));
verifyResults(Arrays.asList(new Object[] { true, "testit", false }), actual);
}
@Test
public void testSMove() {
convertResultToSet = true;
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sAdd("otherset", "bar"));
actual.add(connection.sMove("myset", "otherset", "foo"));
actual.add(connection.sMembers("otherset"));
verifyResults(
Arrays.asList(new Object[] { 1l, 1l, 1l, true,
new HashSet<String>(Arrays.asList(new String[] { "foo", "bar" })) }),
actual);
}
@Test
public void testHKeys() {
actual.add(connection.hSet("test", "key", "2"));
actual.add(connection.hSet("test", "key2", "2"));
actual.add(connection.hKeys("test"));
verifyResults(
Arrays.asList(new Object[] { true, true,
Arrays.asList(new String[] { "key", "key2" }) }), actual);
}
@Test
public void testHSetNX() throws Exception {
actual.add(connection.hSetNX("myhash", "key1", "foo"));
actual.add(connection.hSetNX("myhash", "key1", "bar"));
actual.add(connection.hGet("myhash", "key1"));
verifyResults(Arrays.asList(new Object[] { true, false, "foo" }), actual);
}
@Test
public void testHIncrBy() {
actual.add(connection.hSet("test", "key", "2"));
actual.add(connection.hIncrBy("test", "key", 3l));
actual.add(connection.hGet("test", "key"));
verifyResults(Arrays.asList(new Object[] { true, 5l, "5" }), actual);
}
@Test
public void testHLen() {
actual.add(connection.hSet("test", "key", "2"));
actual.add(connection.hSet("test", "key2", "2"));
actual.add(connection.hLen("test"));
verifyResults(Arrays.asList(new Object[] { true, true, 2l }), actual);
}
@Test
public void testHVals() {
actual.add(connection.hSet("test", "key", "foo"));
actual.add(connection.hSet("test", "key2", "bar"));
actual.add(connection.hVals("test"));
verifyResults(
Arrays.asList(new Object[] { true, true,
Arrays.asList(new String[] { "foo", "bar" }) }), actual);
}
@Test
public void testHDel() throws Exception {
actual.add(connection.hSet("test", "key", "val"));
actual.add(connection.hDel("test", "key"));
actual.add(connection.hDel("test", "foo"));
actual.add(connection.hExists("test", "key"));
verifyResults(Arrays.asList(new Object[] { true, 1l, 0l, false }), actual);
}
@Test
@IfProfileValue(name = "runLongTests", value = "true")
public void testPersist() throws Exception {
connection.set("exp3", "true");
actual.add(connection.expire("exp3", 1));
actual.add(connection.persist("exp3"));
verifyResults(Arrays.asList(new Object[] { true, true }), actual);
Thread.sleep(1500);
assertTrue(connection.exists("exp3"));
}
@Test
@IfProfileValue(name = "runLongTests", value = "true")
public void testExpireAt() throws Exception {
connection.set("exp2", "true");
actual.add(connection.expireAt("exp2", System.currentTimeMillis() / 1000 + 1));
verifyResults(Arrays.asList(new Object[] { true}), actual);
assertTrue(waitFor(new KeyExpired("exp2"), 2500l));
}
@Test
@IfProfileValue(name = "runLongTests", value = "true")
public void testExpire() throws Exception {
connection.set("exp", "true");
actual.add(connection.expire("exp", 1));
verifyResults(Arrays.asList(new Object[] { true }), actual);
assertTrue(waitFor(new KeyExpired("exp"), 2500));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testPExpire() {
connection.set("exp", "true");
actual.add(connection.pExpire("exp", 100));
verifyResults(Arrays.asList(new Object[] { true }), actual);
assertTrue(waitFor(new KeyExpired("exp"), 1000l));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testPExpireKeyNotExists() {
actual.add(connection.pExpire("nonexistent", 100));
verifyResults(Arrays.asList(new Object[] { false }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testPExpireAt() {
connection.set("exp2", "true");
actual.add(connection.pExpireAt("exp2", System.currentTimeMillis() + 200));
verifyResults(Arrays.asList(new Object[] { true }), actual);
assertTrue(waitFor(new KeyExpired("exp2"), 1000l));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testPExpireAtKeyNotExists() {
actual.add(connection.pExpireAt("nonexistent", System.currentTimeMillis() + 200));
verifyResults(Arrays.asList(new Object[] { false }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testPTtl() {
connection.set("whatup", "yo");
actual.add(connection.pExpire("whatup", 9000l));
verifyResults(Arrays.asList(new Object[] { true }), actual);
assertTrue(waitFor(new TestCondition() {
public boolean passes() {
return (connection.pTtl("whatup") > -1);
}
}, 1000l));
}
// LettuceConnection throws an UnsupportedOpException before we close the pipeline
@Test(expected=UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
@@ -395,31 +80,44 @@ public class LettuceConnectionPipelineIntegrationTests extends
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnFalse() {
// Lettuce actually returns booleans, it's not an SDR conversion
actual.add(connection.eval("return false", ReturnType.BOOLEAN, 0));
verifyResults(Arrays.asList(new Object[] { false }), actual);
public void testWatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
//Give some time for watch to be asynch executed
Thread.sleep(500);
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
conn2.close();
connection.multi();
connection.set("testitnow", "somethingelse");
actual.add(connection.exec());
actual.add(connection.get("testitnow"));
// Exec results lost on flatten in closePipeline and also won't get converted
// by DefaultStringRedisConnection yet
List<Object> results = getResults();
assertEquals("something", new String((byte[])results.get(0)));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnTrue() {
// Lettuce actually returns booleans, it's not an SDR conversion
actual.add(connection.eval("return true", ReturnType.BOOLEAN, 0));
verifyResults(Arrays.asList(new Object[] { true }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptFlush() {
getResults();
String sha1 = connection.scriptLoad("return KEYS[1]");
initConnection();
connection.scriptFlush();
actual.add(connection.scriptExists(sha1));
// Lettuce actually returns booleans, it's not an SDR conversion
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new Object[] { false })}), actual);
public void testUnwatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
connection.unwatch();
connection.multi();
//Give some time for unwatch to be asynch executed
Thread.sleep(500);
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
connection.set("testitnow", "somethingelse");
connection.get("testitnow");
connection.exec();
// Exec results lost on flatten in closePipeline and also won't get converted
// by DefaultStringRedisConnection yet
List<Object> results = getResults();
assertEquals(1,results.size());
assertEquals("somethingelse",new String((byte[])results.get(0)));;
}
@Test
@@ -431,6 +129,7 @@ public class LettuceConnectionPipelineIntegrationTests extends
final AtomicBoolean scriptDead = new AtomicBoolean(false);
Thread th = new Thread(new Runnable() {
public void run() {
// Use separate conn factory to avoid using the underlying shared native conn on blocking script
final LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(),
SettingsUtils.getPort());
factory2.afterPropertiesSet();
@@ -459,7 +158,7 @@ public class LettuceConnectionPipelineIntegrationTests extends
public void testMove() {
connection.set("foo", "bar");
actual.add(connection.move("foo", 1));
verifyResults(Arrays.asList(new Object[] { true}), actual);
verifyResults(Arrays.asList(new Object[] { true}));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
factory2.setDatabase(1);
@@ -474,25 +173,4 @@ public class LettuceConnectionPipelineIntegrationTests extends
conn2.close();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
Object convertedResult = super.convertResult(result);
if (convertedResult instanceof KeyValue) {
List<String> keyValue = new ArrayList<String>();
keyValue.add((String) super.convertResult(((KeyValue) convertedResult).key));
keyValue.add((String) super.convertResult(((KeyValue) convertedResult).value));
return keyValue;
} else if (convertedResult instanceof List && !(((List) result).isEmpty())
&& ((List) convertedResult).get(0) instanceof ScoredValue) {
List<StringTuple> tuples = new ArrayList<StringTuple>();
for (ScoredValue value : ((List<ScoredValue>) convertedResult)) {
DefaultStringTuple tuple = new DefaultStringTuple((byte[]) value.value, new String(
(byte[]) value.value), value.score);
tuples.add(tuple);
}
return tuples;
}
return convertedResult;
}
}

View File

@@ -1,18 +1,25 @@
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.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Map;
import java.util.Set;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.redis.connection.DefaultStringTuple;
import org.springframework.data.redis.connection.RedisPipelineException;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.data.redis.connection.convert.SetConverter;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.test.annotation.IfProfileValue;
/**
@@ -22,98 +29,207 @@ import org.springframework.test.annotation.IfProfileValue;
*
*/
public class LettuceConnectionPipelineTxIntegrationTests extends
LettuceConnectionTransactionIntegrationTests {
LettuceConnectionPipelineIntegrationTests {
private boolean convert=true;
private boolean convertToStringTuple=true;
@Ignore
public void testMultiDiscard() {
}
@Ignore
public void testMultiExec() {
}
@Ignore
public void testUnwatch() {
}
@Ignore
public void testWatch() {
}
/*
* Using blocking ops inside a tx does not make a lot of sense as it would
* require blocking the entire server in order to execute the block
* atomically, which in turn does not allow other clients to perform a push
* operation. *
*/
@Ignore
public void testBLPop() {
}
@Ignore
public void testBRPop() {
}
@Ignore
public void testBRPopLPush() {
}
@Ignore
public void testBLPopTimeout() {
}
@Ignore
public void testBRPopTimeout() {
}
@Ignore
public void testBRPopLPushTimeout() {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithNamedChannels() throws Exception {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithPatterns() throws Exception {
}
@Ignore
public void testNullKey() throws Exception {
}
@Ignore
public void testNullValue() throws Exception {
}
@Ignore
public void testHashNullKey() throws Exception {
}
@Ignore
public void testHashNullValue() throws Exception {
}
// Lettuce closePipeline() is now returning converted data types for executed txs, but
// DefaultStringRedisConnection isn't converting byte[]s from exec() yet.
// We implement the conversion in convertResult(), but convertResult's a bit over-eager in certain scenarios, hence these overrides
@Test(expected = RedisPipelineException.class)
public void exceptionExecuteNative() throws Exception {
connection.execute("ZadD", getClass() + "#foo\t0.90\titem");
getResults();
}
@Test
public void testDbSize() {
connection.set("dbparam", "foo");
assertNull(connection.dbSize());
List<Object> results = getResults();
assertEquals(3, results.size());
assertTrue((Long) results.get(2) > 0);
}
@Test
public void testInfo() throws Exception {
assertNull(connection.info());
List<Object> 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
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testInfoBySection() throws Exception {
assertNull(connection.info("server"));
List<Object> 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<Object> results = getResults();
initConnection();
connection.restore("testing".getBytes(), 0, (byte[]) results.get(2));
try {
getResults();
fail("Expected RedisPipelineException restoring existing key");
}catch(RedisPipelineException e) {
}
}
@Test(expected=RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaNotFound() {
connection.evalSha("somefakesha", ReturnType.VALUE, 2, "key1", "key2");
getResults();
}
@Test(expected=RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleError() {
connection.eval("return redis.call('expire','foo')", ReturnType.BOOLEAN, 0);
getResults();
convert = false;
super.testRestoreExistingKey();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleOK() {
actual.add(connection.eval("return redis.call('set','abc','ghk')", ReturnType.STATUS, 0));
// We pipeline the result of multi, so add an extra OK here
assertEquals(Arrays.asList(new Object[] { "OK", "OK" }), convertResults(false));
public void testScriptLoadEvalSha() {
convert = false;
super.testScriptLoadEvalSha();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaArrayStrings() {
convert = false;
super.testEvalShaArrayStrings();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnString() {
convert = false;
super.testEvalReturnString();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayStrings() {
convert = false;
super.testEvalReturnArrayStrings();
}
@SuppressWarnings("unchecked")
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayOKs() {
actual.add(connection.eval("return { redis.call('set','abc','ghk'), redis.call('set','abc','lfdf')}",
actual.add(connection.eval(
"return { redis.call('set','abc','ghk'), redis.call('set','abc','lfdf')}",
ReturnType.MULTI, 0));
// We pipeline the result of multi, so add an extra OK here
assertEquals(Arrays.asList(new Object[] {"OK", Arrays.asList(new Object[] {"OK", "OK"} )}), convertResults(false));
List<String> result = (List<String>) getResults().get(0);
assertEquals(Arrays.asList(new Object[] { "OK", "OK" }), result);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testDumpAndRestore() {
convert = false;
connection.set("testing", "12");
actual.add(connection.dump("testing".getBytes()));
List<Object> 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"));
results = getResults();
assertEquals(3,results.size());
assertEquals(1l, results.get(0));
assertNull(results.get(1));
assertEquals("12", new String((byte[])results.get(2)));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreTtl() {
convert = false;
super.testRestoreTtl();
}
@Test
public void testExecute() {
convert = false;
super.testExecute();
}
@Test
public void testExecuteNoArgs() {
convert = false;
super.testExecuteNoArgs();
}
@SuppressWarnings("unchecked")
@Test
public void testZRevRangeByScoreOffsetCount() {
actual.add(byteConnection.zAdd("myset".getBytes(), 2, "Bob".getBytes()));
actual.add(byteConnection.zAdd("myset".getBytes(), 1, "James".getBytes()));
actual.add(byteConnection.zRevRangeByScore("myset".getBytes(), 0d, 3d, 0, 5));
assertEquals(new LinkedHashSet<String>(Arrays.asList(new String[] { "Bob", "James" })),(Set<String>) getResults().get(2));
}
@SuppressWarnings("unchecked")
@Test
public void testZRevRangeByScore() {
actual.add(byteConnection.zAdd("myset".getBytes(), 2, "Bob".getBytes()));
actual.add(byteConnection.zAdd("myset".getBytes(), 1, "James".getBytes()));
actual.add(byteConnection.zRevRangeByScore("myset".getBytes(), 0d, 3d));
assertEquals(new LinkedHashSet<String>(Arrays.asList(new String[] { "Bob", "James" })), (Set<String>) getResults().get(2));
}
@Test
public void testZRevRangeByScoreWithScoresOffsetCount() {
convertToStringTuple = false;
super.testZRevRangeByScoreWithScoresOffsetCount();
}
@Test
public void testZRevRangeByScoreWithScores() {
convertToStringTuple = false;
super.testZRevRangeByScoreWithScores();
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptKill() {
// Impossible to call script kill in a tx because you can't issue the
// exec command while Redis is running a script
connection.scriptKill();
}
protected void initConnection() {
@@ -123,7 +239,47 @@ public class LettuceConnectionPipelineTxIntegrationTests extends
protected List<Object> getResults() {
assertNull(connection.exec());
return connection.closePipeline();
List<Object> pipelined = connection.closePipeline();
List<Object> convertedResults = new ArrayList<Object>();
for(Object result: pipelined) {
convertedResults.add(convertResult(result));
}
return convertedResults;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
if(!convert) {
return result;
}
if (result instanceof List && !(((List) result).isEmpty())
&& ((List) result).get(0) instanceof byte[]) {
return (SerializationUtils.deserialize((List<byte[]>) result, stringSerializer));
} else if (result instanceof byte[]) {
return (stringSerializer.deserialize((byte[]) result));
} else if (result instanceof Map
&& ((Map) result).keySet().iterator().next() instanceof byte[]) {
return (SerializationUtils.deserialize((Map) result, stringSerializer));
} else if (result instanceof Set && !(((Set) result).isEmpty())) {
Object firstResult = ((Set) result).iterator().next();
if(firstResult instanceof byte[]) {
return (SerializationUtils.deserialize((Set) result, stringSerializer));
}
}
if (result instanceof Set && !(((Set) result).isEmpty())
&& ((Set) result).iterator().next() instanceof Tuple) {
if(convertToStringTuple) {
return new SetConverter<Tuple, StringTuple>(new TupleConverter())
.convert((Set)result);
}
}
return result;
}
private class TupleConverter implements Converter<Tuple, StringTuple> {
public StringTuple convert(Tuple source) {
return new DefaultStringTuple(source, stringSerializer.deserialize(source.getValue()));
}
}
}

View File

@@ -15,20 +15,34 @@
*/
package org.springframework.data.redis.connection.lettuce;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.AbstractConnectionTransactionIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.DefaultStringTuple;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.data.redis.connection.convert.SetConverter;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.lambdaworks.redis.RedisException;
import com.lambdaworks.redis.KeyValue;
import com.lambdaworks.redis.ScoredValue;
/**
* Integration test of {@link LettuceConnection} functionality within a
@@ -40,118 +54,313 @@ import com.lambdaworks.redis.RedisException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("LettuceConnectionIntegrationTests-context.xml")
public class LettuceConnectionTransactionIntegrationTests extends
LettuceConnectionPipelineIntegrationTests {
AbstractConnectionTransactionIntegrationTests {
private boolean convertListToSet;
private boolean convertToStringTuple=true;
@Ignore
public void testMultiDiscard() {
public void testMultiConnectionsOneInTx() {
}
@Ignore
public void testMultiExec() {
public void testCloseBlockingOps() {
}
@Ignore
public void testUnwatch() {
// Native Lettuce returns ZSets as Lists
@Test
public void testZAddAndZRange() {
convertListToSet = true;
super.testZAddAndZRange();
}
@Ignore
public void testWatch() {
@Test
public void testZIncrBy() {
convertListToSet = true;
super.testZIncrBy();
}
/*
* Using blocking ops inside a tx does not make a lot of sense as it would
* require blocking the entire server in order to execute the block
* atomically, which in turn does not allow other clients to perform a push
* operation. Also, Lettuce always times out in these scenarios b/c it waits
* for an actual response instead of accepting the null returned by op in tx
* *
*/
@Ignore
public void testBLPop() {
@Test
public void testZInterStore() {
convertListToSet = true;
super.testZInterStore();
}
@Ignore
public void testBRPop() {
@Test
public void testZInterStoreAggWeights() {
convertListToSet = true;
super.testZInterStoreAggWeights();
}
@Ignore
public void testBRPopLPush() {
@Test
public void testZRangeWithScores() {
convertListToSet = true;
super.testZRangeWithScores();
}
@Ignore
public void testBLPopTimeout() {
@Test
public void testZRangeByScore() {
convertListToSet = true;
super.testZRangeByScore();
}
@Ignore
public void testBRPopTimeout() {
@Test
public void testZRangeByScoreOffsetCount() {
convertListToSet = true;
super.testZRangeByScoreOffsetCount();
}
@Ignore
public void testBRPopLPushTimeout() {
@Test
public void testZRangeByScoreWithScores() {
convertListToSet = true;
super.testZRangeByScoreWithScores();
}
@Ignore
public void testOpenPipelineTwice() {
@Test
public void testZRangeByScoreWithScoresOffsetCount() {
convertListToSet = true;
super.testZRangeByScoreWithScoresOffsetCount();
}
@Test
public void testZRevRange() {
convertListToSet = true;
super.testZRevRange();
}
@Test
public void testZRevRangeWithScores() {
convertListToSet = true;
super.testZRevRangeWithScores();
}
@Test
public void testZRem() {
convertListToSet = true;
super.testZRem();
}
@Test
public void testZRemRangeByRank() {
convertListToSet = true;
super.testZRemRangeByRank();
}
@Test
public void testZRemRangeByScore() {
convertListToSet = true;
super.testZRemRangeByScore();
}
@Test
public void testZUnionStore() {
convertListToSet = true;
super.testZUnionStore();
}
@Test
public void testZUnionStoreAggWeights() {
convertListToSet = true;
super.testZUnionStoreAggWeights();
}
@Test
public void testBitSet() throws Exception {
convertLongToBoolean = false;
String key = "bitset-test";
connection.setBit(key, 0, false);
connection.setBit(key, 1, true);
actual.add(connection.getBit(key, 0));
actual.add(connection.getBit(key, 1));
// Lettuce setBit returns Long instead of void
verifyResults(Arrays.asList(new Object[] { 0l, 0l, 0l, 1l }));
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testBitCount() {
convertLongToBoolean = false;
String key = "bitset-test";
connection.setBit(key, 0, false);
connection.setBit(key, 1, true);
connection.setBit(key, 2, true);
actual.add(connection.bitCount(key));
// Lettuce setBit returns Long instead of void
verifyResults(new ArrayList<Object>(Arrays.asList(0l, 0l, 0l, 2l)));
}
@Test
public void testHKeys() {
convertListToSet = true;
super.testHKeys();
}
@Test(expected = UnsupportedOperationException.class)
public void testBitOpNotMultipleSources() {
super.testBitOpNotMultipleSources();
}
@Test
public void exceptionExecuteNative() throws Exception {
connection.execute("ZadD", getClass() + "#foo\t0.90\titem");
// Syntax error on queued commands are swallowed and no results are returned
// Syntax error on queued commands are swallowed and no results are
// returned
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<Object> 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<Object> results = getResults();
initConnection();
connection.restore("testing".getBytes(), 0, (byte[]) results.get(1));
List<Object> restoreResults = getResults();
assertTrue(restoreResults.get(0) instanceof RedisException);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaNotFound() {
connection.evalSha("somefakesha", ReturnType.VALUE, 2, "key1", "key2");
List<Object> results = getResults();
assertTrue(results.get(0) instanceof RedisException);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleError() {
connection.eval("return redis.call('expire','foo')", ReturnType.BOOLEAN, 0);
List<Object> results = getResults();
assertTrue(results.get(0) instanceof RedisException);
public void testGetRangeSetRange() {
connection.set("rangekey", "supercalifrag");
actual.add(connection.getRange("rangekey", 0l, 2l));
connection.setRange("rangekey", "ck", 2);
actual.add(connection.get("rangekey"));
// Lettuce returns a value for setRange
verifyResults(Arrays.asList(new Object[] { "sup", 13l, "suckrcalifrag" }));
}
@Test(expected = UnsupportedOperationException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptKill() {
// Impossible to call script kill in a tx because you can't issue the
// exec command while Redis is running a script
connection.scriptKill();
public void testSRandMemberCountNegative() {
super.testSRandMemberCountNegative();
}
protected void initConnection() {
connection.multi();
@Test
public void testSortStoreNullParams() {
convertLongToBoolean = false;
super.testSortStoreNullParams();
}
protected List<Object> getResults() {
return connection.exec();
@SuppressWarnings("unchecked")
@Test
public void testZRevRangeByScoreOffsetCount() {
actual.add(byteConnection.zAdd("myset".getBytes(), 2, "Bob".getBytes()));
actual.add(byteConnection.zAdd("myset".getBytes(), 1, "James".getBytes()));
actual.add(byteConnection.zRevRangeByScore("myset".getBytes(), 0d, 3d, 0, 5));
assertEquals(Arrays.asList(new String[] { "Bob", "James" }),(List<String>) getResults().get(2));
}
@SuppressWarnings("unchecked")
@Test
public void testZRevRangeByScore() {
actual.add(byteConnection.zAdd("myset".getBytes(), 2, "Bob".getBytes()));
actual.add(byteConnection.zAdd("myset".getBytes(), 1, "James".getBytes()));
actual.add(byteConnection.zRevRangeByScore("myset".getBytes(), 0d, 3d));
assertEquals(Arrays.asList(new String[] { "Bob", "James" }), (List<String>) getResults().get(2));
}
@SuppressWarnings("unchecked")
@Test
public void testZRevRangeByScoreWithScoresOffsetCount() {
actual.add(byteConnection.zAdd("myset".getBytes(), 2, "Bob".getBytes()));
actual.add(byteConnection.zAdd("myset".getBytes(), 1, "James".getBytes()));
actual.add(byteConnection.zRevRangeByScore("myset".getBytes(), 0d, 3d, 0, 5));
assertEquals(Arrays.asList(new String[] { "Bob", "James" }),
(List<byte[]>) getResults().get(2));
}
@Test
public void testZRevRangeByScoreWithScores() {
convertToStringTuple = false;
super.testZRevRangeByScoreWithScores();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleOK() {
actual.add(connection.eval("return redis.call('set','abc','ghk')", ReturnType.STATUS, 0));
assertEquals(Arrays.asList(new Object[] { "OK" }), connection.exec());
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testDumpAndRestore() {
convert = false;
connection.set("testing", "12");
actual.add(connection.dump("testing".getBytes()));
List<Object> 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"));
results = getResults();
assertEquals(3,results.size());
assertEquals(1l, results.get(0));
assertNull(results.get(1));
assertEquals("12", new String((byte[])results.get(2)));
}
@SuppressWarnings("unchecked")
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayOKs() {
actual.add(connection.eval(
"return { redis.call('set','abc','ghk'), redis.call('set','abc','lfdf')}",
ReturnType.MULTI, 0));
List<String> result = (List<String>) getResults().get(0);
assertEquals(Arrays.asList(new Object[] { "OK", "OK" }), result);
}
@Test
public void testMove() {
connection.set("foo", "bar");
actual.add(connection.move("foo", 1));
verifyResults(Arrays.asList(new Object[] { true}));
// Lettuce does not support select when using shared conn, use a new conn factory
LettuceConnectionFactory factory2 = new LettuceConnectionFactory();
factory2.setDatabase(1);
factory2.afterPropertiesSet();
StringRedisConnection conn2 = new DefaultStringRedisConnection(factory2.getConnection());
try {
assertEquals("bar",conn2.get("foo"));
} finally {
if(conn2.exists("foo")) {
conn2.del("foo");
}
conn2.close();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected Object convertResult(Object result) {
if (!convert) {
return result;
}
Object convertedResult = super.convertResult(result);
if (convertedResult instanceof KeyValue) {
List<String> keyValue = new ArrayList<String>();
keyValue.add((String) super.convertResult(((KeyValue) convertedResult).key));
keyValue.add((String) super.convertResult(((KeyValue) convertedResult).value));
return keyValue;
}
if (convertedResult instanceof List && !(((List) result).isEmpty())
&& ((List) convertedResult).get(0) instanceof ScoredValue) {
Set<Tuple> tuples = LettuceConverters.toTupleSet((List) convertedResult);
if(convertToStringTuple) {
return new SetConverter<Tuple, StringTuple>(new TupleConverter())
.convert(tuples);
}
return tuples;
}
if (convertListToSet && convertedResult instanceof List) {
return new LinkedHashSet((List) convertedResult);
}
if (convertStringToProps && convertedResult instanceof String) {
return LettuceConverters.toProperties((String) convertedResult);
}
return convertedResult;
}
private class TupleConverter implements Converter<Tuple, StringTuple> {
public StringTuple convert(Tuple source) {
return new DefaultStringTuple(source, stringSerializer.deserialize(source.getValue()));
}
}
@Override
protected DataAccessException convertException(Exception ex) {
return LettuceConverters.toDataAccessException(ex);
}
}

View File

@@ -17,13 +17,16 @@
package org.springframework.data.redis.connection.srp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
@@ -66,18 +69,15 @@ public class SrpConnectionIntegrationTests extends AbstractConnectionIntegration
@Test
@IfProfileValue(name = "redisVersion", values = {"2.4", "2.6"})
public void testGetRangeSetRange() {
// SRP throws an Exception if you try to execute on version lower than 2.4
super.testGetRangeSetRange();
}
@Test
public void testExecute() {
connection.set("foo", "bar");
assertEquals("bar", stringSerializer.deserialize((byte[])connection.execute("GET", "foo")));
}
@Test
public void testExecuteNoArgs() {
assertEquals("PONG", connection.execute("PING"));
// SRP returns this as String while other drivers return as byte[]
actual.add(connection.execute("PING"));
verifyResults(Arrays.asList(new Object[] { "PONG" }));
}
@Test
@@ -86,6 +86,43 @@ public class SrpConnectionIntegrationTests extends AbstractConnectionIntegration
// SRP returns the Strings from individual StatusReplys in a MultiBulkReply, while other clients return as byte[]
actual.add(connection.eval("return { redis.call('set','abc','ghk'), redis.call('set','abc','lfdf')}",
ReturnType.MULTI, 0));
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new Object[] {"OK", "OK"} )}), actual);
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new Object[] {"OK", "OK"} )}));
}
@SuppressWarnings("unchecked")
@Test
public void testMultiExec() throws Exception {
connection.multi();
connection.set("key", "value");
actual.add(connection.get("key"));
actual.add(connection.exec());
List<Object> results = getResults();
assertNull(results.get(0));
List<Object> execResults = (List<Object>) results.get(1);
// SRP is already filtering out the void types since tx uses pipeline, so result size here is only 1
assertEquals(1, execResults.size());
// However, since DefaultStringRedisConnection doesn't yet convert tx results, the data is still in raw bytes
assertEquals("value", new String((byte[]) execResults.get(0)));
assertEquals("value", connection.get("key"));
}
@SuppressWarnings("unchecked")
@Test
public void testUnwatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
connection.unwatch();
connection.multi();
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
connection.set("testitnow", "somethingelse");
actual.add(connection.get("testitnow"));
actual.add(connection.exec());
List<Object> results = getResults();
assertNull(results.get(0));
List<Object> execResults = (List<Object>) results.get(1);
// SRP is already filtering out the void types since tx uses pipeline, so result size here is only 1
assertEquals("somethingelse", new String((byte[]) execResults.get(0)));
}
}

View File

@@ -16,36 +16,20 @@
package org.springframework.data.redis.connection.srp;
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.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
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.RedisPipelineException;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import redis.reply.BulkReply;
import redis.reply.IntegerReply;
import redis.reply.Reply;
import redis.reply.StatusReply;
/**
* Integration test of {@link SrpConnection} pipeline functionality
*
@@ -65,11 +49,12 @@ public class SrpConnectionPipelineIntegrationTests extends
connection.multi();
connection.set("testitnow2", "notok");
connection.discard();
// SRP throws Exception on transaction discard, so we expect pipeline exception here
// SRP throws Exception on transaction discard, so we expect pipeline
// exception here
try {
getResults();
fail("Closing the pipeline on a discarded tx should throw a RedisPipelineException");
}catch(RedisPipelineException e) {
} catch (RedisPipelineException e) {
}
assertEquals("willdo", connection.get("testitnow"));
connection.openPipeline();
@@ -77,23 +62,30 @@ public class SrpConnectionPipelineIntegrationTests extends
testMultiExec();
}
// SRP sets results of all commands in the pipeline to RedisException if exec returns a
// SRP sets results of all commands in the pipeline to RedisException if
// exec returns a
// null multi-bulk reply
@Test(expected=RedisPipelineException.class)
@Test(expected = RedisPipelineException.class)
public void testWatch() throws Exception {
connection.set("testitnow", "willdo");
connection.watch("testitnow".getBytes());
//Give some time for watch to be asynch executed
Thread.sleep(500);
DefaultStringRedisConnection conn2 = new DefaultStringRedisConnection(
connectionFactory.getConnection());
conn2.set("testitnow", "something");
conn2.close();
connection.multi();
connection.set("testitnow", "somethingelse");
actual.add(connection.exec());
actual.add(connection.get("testitnow"));
verifyResults(Arrays.asList(new Object[] { null, "something" }), actual);
super.testWatch();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayOKs() {
// SRP returns the Strings from individual StatusReplys in a
// MultiBulkReply, while other clients return as byte[]
actual.add(connection.eval(
"return { redis.call('set','abc','ghk'), redis.call('set','abc','lfdf')}",
ReturnType.MULTI, 0));
verifyResults(Arrays.asList(new Object[] { Arrays.asList(new Object[] { "OK", "OK" }) }));
}
@Test
public void testExecuteNoArgs() {
// SRP returns this as String while other drivers return as byte[]
actual.add(connection.execute("PING"));
verifyResults(Arrays.asList(new Object[] { "PONG" }));
}
@Test(expected = UnsupportedOperationException.class)
@@ -105,147 +97,4 @@ public class SrpConnectionPipelineIntegrationTests extends
public void testZUnionStoreAggWeights() {
super.testZUnionStoreAggWeights();
}
// Overrides, usually due to return values being Long vs Boolean or Set vs
// List
@Test
public void testInfo() throws Exception {
assertNull(connection.info());
List<Object> results = getResults();
assertEquals(1, results.size());
Properties info = SrpUtils.info(new BulkReply((byte[]) results.get(0)));
assertTrue("at least 5 settings should be present", info.size() >= 5);
String version = info.getProperty("redis_version");
assertNotNull(version);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testInfoBySection() throws Exception {
assertNull(connection.info("server"));
List<Object> results = getResults();
assertEquals(1, results.size());
Properties info = SrpUtils.info(new BulkReply((byte[]) results.get(0)));
assertTrue("at least 5 settings should be present", info.size() >= 5);
String version = info.getProperty("redis_version");
assertNotNull(version);
}
@Test
public void testExists() {
connection.set("existent", "true");
actual.add(connection.exists("existent"));
actual.add(connection.exists("nonexistent"));
verifyResults(Arrays.asList(new Object[] { 1l, 0l }), actual);
}
@Test
public void testRename() {
connection.set("renametest", "testit");
connection.rename("renametest", "newrenametest");
actual.add(connection.get("newrenametest"));
actual.add(connection.exists("renametest"));
verifyResults(Arrays.asList(new Object[] { "testit", 0l }), actual);
}
@Test
public void testSIsMember() {
convertResultToSet = true;
actual.add(connection.sAdd("myset", "foo"));
actual.add(connection.sAdd("myset", "bar"));
actual.add(connection.sIsMember("myset", "foo"));
actual.add(connection.sIsMember("myset", "baz"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 0l }), actual);
}
@Test
public void testZIncrBy() {
actual.add(connection.zAdd("myset", 2, "Bob"));
actual.add(connection.zAdd("myset", 1, "James"));
actual.add(connection.zAdd("myset", 4, "Joe"));
actual.add(connection.zIncrBy("myset", 2, "Joe"));
actual.add(connection.zRangeByScore("myset", 6, 6));
verifyResults(
Arrays.asList(new Object[] { 1l, 1l, 1l, "6", Collections.singletonList("Joe") }),
actual);
}
@Test
public void testZScore() {
actual.add(connection.zAdd("myset", 2, "Bob"));
actual.add(connection.zAdd("myset", 1, "James"));
actual.add(connection.zAdd("myset", 3, "Joe"));
actual.add(connection.zScore("myset", "Joe"));
verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, "3" }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", values = {"2.4", "2.6"})
public void testGetRangeSetRange() {
super.testGetRangeSetRange();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testIncrByDouble() {
connection.set("tdb", "4.5");
actual.add(connection.incrBy("tdb", 7.2));
actual.add(connection.get("tdb"));
// pipelined incrBy returns value as a byte[] instead of Double
verifyResults(Arrays.asList(new Object[] { "11.7" , "11.7" }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testHIncrByDouble() {
actual.add(connection.hSet("test", "key", "2.9"));
actual.add(connection.hIncrBy("test", "key", 3.5));
actual.add(connection.hGet("test", "key"));
// pipelined hIncrBy returns value as a byte[] instead of Double
verifyResults(Arrays.asList(new Object[] { 1l, "6.4", "6.4" }), actual);
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testScriptExists() {
getResults();
String sha1 = connection.scriptLoad("return 'foo'");
initConnection();
actual.add(connection.scriptExists(sha1, "98777234"));
verifyResults(Arrays.asList(new Object[] {Arrays.asList(new Object[] {1l, 0l})}), actual);
}
@Test
public void testDel() {
connection.set("testing","123");
actual.add(connection.del("testing"));
actual.add(connection.exists("testing"));
verifyResults(Arrays.asList(new Object[] { 1l, 0l }), actual);
}
protected Object convertResult(Object result) {
Object convertedResult = super.convertResult(result);
if (convertedResult instanceof Reply[]) {
if (convertResultToSet) {
return SerializationUtils.deserialize(SrpUtils.toSet((Reply[]) convertedResult),
stringSerializer);
} else if (convertResultToTuples) {
Set<Tuple> tuples = SrpUtils.convertTuple((Reply[]) convertedResult);
List<StringTuple> stringTuples = new ArrayList<StringTuple>();
for (Tuple tuple : tuples) {
stringTuples.add(new DefaultStringTuple(tuple, new String(tuple.getValue())));
}
return stringTuples;
} else if(((Reply[]) convertedResult).length > 0 && ((Reply[])convertedResult)[0] instanceof IntegerReply) {
return SrpUtils.asIntegerList((Reply[])convertedResult);
} else if(((Reply[]) convertedResult).length > 0 && ((Reply[])convertedResult)[0] instanceof StatusReply) {
return SrpUtils.asStatusList((Reply[])convertedResult);
} else {
return SerializationUtils.deserialize(
SrpUtils.toBytesList((Reply[]) convertedResult), stringSerializer);
}
}
return convertedResult;
}
}

View File

@@ -19,15 +19,13 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.RedisVersionUtils;
import org.springframework.data.redis.connection.RedisPipelineException;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
import org.springframework.test.annotation.IfProfileValue;
/**
@@ -69,9 +67,8 @@ public class SrpConnectionPipelineTxIntegrationTests extends SrpConnectionTransa
assertNull(connection.exec());
assertNull(connection.get("foo"));
List<Object> results = connection.closePipeline();
assertEquals(2, results.size());
assertEquals("OK", results.get(0));
assertEquals("bar", new String((byte[]) results.get(1)));
assertEquals(1, results.size());
assertEquals("bar", new String((byte[]) results.get(0)));
assertEquals("bar", connection.get("foo"));
}
@@ -85,67 +82,39 @@ public class SrpConnectionPipelineTxIntegrationTests extends SrpConnectionTransa
assertNull(connection.get("foo"));
assertNull(connection.exec());
List<Object> results = connection.closePipeline();
assertEquals(4, results.size());
assertEquals("OK", results.get(0));
assertEquals("bar", new String((byte[]) results.get(1)));
assertEquals("OK", results.get(2));
assertEquals("baz", new String((byte[]) results.get(3)));
}
@Test
@IfProfileValue(name = "redisVersion", values = {"2.4", "2.6"})
public void testGetRangeSetRange() {
connection.set("rangekey", "supercalifrag");
actual.add(connection.getRange("rangekey", 0l, 2l));
connection.setRange("rangekey", "ck", 2);
actual.add(connection.get("rangekey"));
verifyResults(Arrays.asList(new Object[] { "sup", 13l, "suckrcalifrag" }), actual);
assertEquals(2, results.size());
assertEquals("bar", new String((byte[]) results.get(0)));
assertEquals("baz", new String((byte[]) results.get(1)));
}
@Test(expected=RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaNotFound() {
connection.evalSha("somefakesha", ReturnType.VALUE, 2, "key1", "key2");
getResults();
super.testEvalShaNotFound();
}
@Test(expected=RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleError() {
connection.eval("return redis.call('expire','foo')", ReturnType.BOOLEAN, 0);
getResults();
super.testEvalReturnSingleError();
}
@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
@Test(expected = RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreExistingKey() {
connection.set("testing", "12");
connection.dump("testing".getBytes());
List<Object> 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) {
}
super.testRestoreExistingKey();
}
@Test(expected=RedisPipelineException.class)
@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();
super.testBitOpNotMultipleSources();
}
@Test(expected = RedisPipelineException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreBadData() {
super.testRestoreBadData();
}
protected void initConnection() {
@@ -155,6 +124,12 @@ public class SrpConnectionPipelineTxIntegrationTests extends SrpConnectionTransa
protected List<Object> getResults() {
assertNull(connection.exec());
return connection.closePipeline();
List<Object> actual = connection.closePipeline();
List<Object> serializedResults = new ArrayList<Object>();
for (Object result : actual) {
Object convertedResult = convertResult(result);
serializedResults.add(convertedResult);
}
return serializedResults;
}
}

View File

@@ -15,25 +15,35 @@
*/
package org.springframework.data.redis.connection.srp;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.DefaultStringTuple;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.test.annotation.IfProfileValue;
/**
* Integration test of {@link SrpConnection} functionality within a transaction
*
* @author Jennifer Hickey
*
*/
public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipelineIntegrationTests {
public class SrpConnectionTransactionIntegrationTests extends SrpConnectionIntegrationTests {
private boolean convert = true;
@Ignore
public void testMultiDiscard() {
@@ -48,7 +58,6 @@ public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipel
}
@Ignore
@Test
public void testWatch() {
}
@@ -56,7 +65,7 @@ public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipel
* Using blocking ops inside a tx does not make a lot of sense as it would
* require blocking the entire server in order to execute the block
* atomically, which in turn does not allow other clients to perform a push
* operation.
* operation. *
*/
@Ignore
@@ -83,70 +92,132 @@ public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipel
public void testBRPopLPushTimeout() {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithNamedChannels() throws Exception {
}
@Ignore("Pub/Sub not supported with transactions")
public void testPubSubWithPatterns() throws Exception {
}
@Ignore
public void testOpenPipelineTwice() {
public void testNullKey() throws Exception {
}
@Ignore
public void testNullValue() throws Exception {
}
@Ignore
public void testHashNullKey() throws Exception {
}
@Ignore
public void testHashNullValue() throws Exception {
}
@Test(expected = RedisSystemException.class)
public void exceptionExecuteNative() throws Exception {
connection.execute("ZadD", getClass() + "#foo\t0.90\titem");
getResults();
super.exceptionExecuteNative();
}
// SRP tx.exec() is now returning converted data types b/c it uses pipeline, but
// DefaultStringRedisConnection isn't converting byte[]s from exec() yet.
// We implement the conversion in convertResult(), but convertResult's a bit over-eager in certain scenarios, hence these overrides
@Test
public void testExecute() {
convert = false;
super.testExecute();
}
@Test
@IfProfileValue(name = "redisVersion", values = { "2.4", "2.6" })
public void testGetRangeSetRange() {
connection.set("rangekey", "supercalifrag");
actual.add(connection.getRange("rangekey", 0l, 2l));
connection.setRange("rangekey", "ck", 2);
actual.add(connection.get("rangekey"));
verifyResults(Arrays.asList(new Object[] { "sup", 13l, "suckrcalifrag" }), actual);
}
@Test(expected=RedisSystemException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnSingleError() {
connection.eval("return redis.call('expire','foo')", ReturnType.BOOLEAN, 0);
getResults();
}
@Test(expected=RedisSystemException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaNotFound() {
connection.evalSha("somefakesha", ReturnType.VALUE, 2, "key1", "key2");
getResults();
}
@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());
getResults();
public void testScriptLoadEvalSha() {
convert = false;
super.testScriptLoadEvalSha();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalShaArrayStrings() {
convert = false;
super.testEvalShaArrayStrings();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnString() {
convert = false;
super.testEvalReturnString();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testEvalReturnArrayStrings() {
convert = false;
super.testEvalReturnArrayStrings();
}
@Test
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testDumpAndRestore() {
convert = false;
connection.set("testing", "12");
actual.add(connection.dump("testing".getBytes()));
List<Object> 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"));
results = getResults();
assertEquals(3,results.size());
assertEquals(1l, results.get(0));
assertNull(results.get(1));
assertEquals("12", new String((byte[])results.get(2)));
}
@Test(expected = RedisSystemException.class)
@IfProfileValue(name = "redisVersion", value = "2.6")
public void testRestoreExistingKey() {
connection.set("testing", "12");
connection.dump("testing".getBytes());
actual.add(connection.dump("testing".getBytes()));
List<Object> results = getResults();
initConnection();
connection.restore("testing".getBytes(), 0, (byte[]) results.get(1));
try {
getResults();
fail("Expected pipeline exception restoring an existing key");
}catch(RedisSystemException e) {
}
connection.restore("testing".getBytes(), 0, ((String)results.get(0)).getBytes());
getResults();
}
@Test(expected=RedisSystemException.class)
@Test
@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();
public void testRestoreTtl() {
convert = false;
super.testRestoreTtl();
}
@Test
public void testZRevRangeByScoreOffsetCount() {
convert = false;
super.testZRevRangeByScoreOffsetCount();
}
@Test
public void testZRevRangeByScore() {
convert = false;
super.testZRevRangeByScore();
}
@Test
public void testZRevRangeByScoreWithScoresOffsetCount() {
convert = false;
super.testZRevRangeByScoreWithScoresOffsetCount();
}
@Test
public void testZRevRangeByScoreWithScores() {
convert = false;
super.testZRevRangeByScoreWithScores();
}
@Test(expected = UnsupportedOperationException.class)
@@ -162,6 +233,52 @@ public class SrpConnectionTransactionIntegrationTests extends SrpConnectionPipel
}
protected List<Object> getResults() {
return connection.exec();
List<Object> actual = connection.exec();
List<Object> serializedResults = new ArrayList<Object>();
for (Object result : actual) {
Object convertedResult = convertResult(result);
serializedResults.add(convertedResult);
}
return serializedResults;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object convertResult(Object result) {
if(! convert) {
return result;
}
if (result instanceof List && !(((List) result).isEmpty())
&& ((List) result).get(0) instanceof byte[]) {
return (SerializationUtils.deserialize((List<byte[]>) result, stringSerializer));
} else if (result instanceof byte[]) {
return (stringSerializer.deserialize((byte[]) result));
} else if (result instanceof Map
&& ((Map) result).keySet().iterator().next() instanceof byte[]) {
return (SerializationUtils.deserialize((Map) result, stringSerializer));
} else if (result instanceof Set && !(((Set) result).isEmpty())) {
Object firstResult = ((Set) result).iterator().next();
if(firstResult instanceof byte[]) {
return (SerializationUtils.deserialize((Set) result, stringSerializer));
}
if(firstResult instanceof Tuple) {
Set<StringTuple> tuples = new LinkedHashSet<StringTuple>();
for (Tuple value : ((Set<Tuple>) result)) {
DefaultStringTuple tuple = new DefaultStringTuple(value,stringSerializer.deserialize(value.getValue()));
tuples.add(tuple);
}
return tuples;
}
}
return result;
}
protected void verifyResults(List<Object> expected) {
List<Object> expectedTx = new ArrayList<Object>();
for (int i = 0; i < actual.size(); i++) {
expectedTx.add(null);
}
assertEquals(expectedTx, actual);
List<Object> results = getResults();
assertEquals(expected, results);
}
}