package com.trigonic.jedis;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static redis.clients.jedis.BinaryClient.LIST_POSITION.AFTER;
import static redis.clients.jedis.BinaryClient.LIST_POSITION.BEFORE;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.SortingParams;
import redis.clients.jedis.ZParams;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
public class NamespaceJedisTest {
private Jedis jedis;
private NamespaceJedisPool namespacedPool;
private Jedis namespaced;
@Before
public void setup() {
jedis = new Jedis("localhost");
jedis.flushDB();
namespacedPool = new NamespaceJedisPool("localhost").withNamespace("ns");
namespaced = namespacedPool.getResource();
jedis.set("foo", "bar");
}
@After
public void tearDown() {
namespacedPool.returnResource(namespaced);
jedis.flushDB();
jedis.quit();
}
@Test
public void shouldBeAbleToUseANamespace() {
assertNull(namespaced.get("foo"));
namespaced.set("foo", "chris");
assertEquals("bar", jedis.get("foo"));
assertEquals("chris", namespaced.get("foo"));
assertEquals("chris", jedis.get("ns:foo"));
jedis.set("foo", "bob");
assertEquals("bob", jedis.get("foo"));
assertEquals("chris", namespaced.get("foo"));
assertEquals("chris", jedis.get("ns:foo"));
namespaced.incrBy("counter", 2);
assertEquals("2", namespaced.get("counter"));
assertNull(jedis.get("counter"));
assertEquals("string", namespaced.type("counter"));
}
@Test
public void shouldBeAbleToUseANamespaceWithBlpop() {
namespaced.rpush("foo", "string");
namespaced.rpush("foo", "ns:string");
assertEquals(Arrays.asList("foo", "string"), namespaced.blpop(1, "foo"));
assertEquals(Arrays.asList("foo", "ns:string"), namespaced.blpop(1, "foo"));
assertNull(namespaced.blpop(1, "foo"));
}
@Test
public void shouldBeAbleToUseANamespaceWithBrpop() {
namespaced.rpush("foo", "string");
namespaced.rpush("foo", "ns:string");
assertEquals(Arrays.asList("foo", "ns:string"), namespaced.brpop(1, "foo"));
assertEquals(Arrays.asList("foo", "string"), namespaced.brpop(1, "foo"));
assertNull(namespaced.blpop(1, "foo"));
}
@Test
public void shouldBeAbleToUseANamespaceWithBrpoplpush() {
namespaced.rpush("foo", "string");
namespaced.rpush("foo", "ns:string");
namespaced.brpoplpush("foo", "bar", 1);
assertEquals(Arrays.asList("foo", "string"), namespaced.brpop(1, "foo"));
assertNull(namespaced.blpop(1, "foo"));
assertEquals(Arrays.asList("bar", "ns:string"), namespaced.brpop(1, "bar"));
assertNull(namespaced.blpop(1, "bar"));
}
@Test
public void shouldBeAbleToUseANamespaceWithDel() {
namespaced.set("foo", "1000");
namespaced.set("bar", "2000");
namespaced.set("baz", "3000");
assertEquals(asSet("foo", "bar", "baz"), namespaced.keys("*"));
namespaced.del("foo");
assertNull(namespaced.get("foo"));
namespaced.del("bar", "baz");
assertNull(namespaced.get("bar"));
assertNull(namespaced.get("baz"));
assertEquals(asSet(), namespaced.keys("*"));
}
@Test
public void shouldBeAbleToUseANamespaceWithDelPipelined() {
Pipeline pipeline = namespaced.pipelined();
pipeline.set("foo", "1000");
pipeline.set("bar", "2000");
pipeline.set("baz", "3000");
Response<Set<String>> response1 = pipeline.keys("*");
pipeline.del("foo");
Response<String> response2 = pipeline.get("foo");
pipeline.del("bar", "baz");
Response<String> response3 = pipeline.get("bar");
Response<String> response4 = pipeline.get("baz");
Response<Set<String>> response5 = pipeline.keys("*");
pipeline.sync();
assertEquals(asSet("foo", "bar", "baz"), response1.get());
assertNull(response2.get());
assertNull(response3.get());
assertNull(response4.get());
assertEquals(asSet(), response5.get());
}
@Test
public void shouldBeAbleToUseANamespaceWithMget() {
namespaced.set("foo", "1000");
namespaced.set("bar", "2000");
assertEquals(asList("1000", "2000"), namespaced.mget("foo", "bar"));
assertEquals(asList("1000", "2000", null), namespaced.mget("foo", "bar", "baz"));
}
@Test
public void shouldBeAbleToUseANamespaceWithMset() {
namespaced.mset("foo", "1000", "bar", "2000");
assertEquals(asList("1000", "2000"), namespaced.mget("foo", "bar"));
assertEquals(asList("1000", "2000", null), namespaced.mget("foo", "bar", "baz"));
}
@Test
public void shouldBeAbleToUseANamespaceWithMsetnx() {
namespaced.msetnx("foo", "1000", "bar", "2000");
assertEquals(asList("1000", "2000"), namespaced.mget("foo", "bar"));
assertEquals(asList("1000", "2000", null), namespaced.mget("foo", "bar", "baz"));
}
@Test
public void shouldBeAbleToUseANamespaceWithHashes() {
namespaced.hset("foo", "key", "value");
namespaced.hset("foo", "key1", "value1");
assertEquals("value", namespaced.hget("foo", "key"));
assertEquals(asMap("key", "value", "key1", "value1"), namespaced.hgetAll("foo"));
assertEquals(Long.valueOf(2), namespaced.hlen("foo"));
assertEquals(asSet("key", "key1"), namespaced.hkeys("foo"));
namespaced.hmset("bar", asMap("key", "value", "key1", "value1"));
namespaced.hmget("bar", "key", "key1");
namespaced.hmset("bar", asMap("a_number", "1"));
assertEquals(asList("1"), namespaced.hmget("bar", "a_number"));
namespaced.hincrBy("bar", "a_number", 3);
assertEquals(asList("4"), namespaced.hmget("bar", "a_number"));
assertEquals(asMap("key", "value", "key1", "value1", "a_number", "4"), namespaced.hgetAll("bar"));
assertEquals(Long.valueOf(1), namespaced.hsetnx("foonx", "nx", "10"));
assertEquals(Long.valueOf(0), namespaced.hsetnx("foonx", "nx", "12"));
assertEquals("10", namespaced.hget("foonx", "nx"));
assertEquals(asSet("nx"), namespaced.hkeys("foonx"));
assertEquals(asList("10"), namespaced.hvals("foonx"));
namespaced.hmset("baz", asMap("key", "value", "key1", "value1", "a_number", "4"));
assertEquals(asMap("key", "value", "key1", "value1", "a_number", "4"), namespaced.hgetAll("baz"));
}
@Test
public void shouldProperlyMoveMemberBetweenSets() {
namespaced.sadd("foo", "1");
namespaced.sadd("foo", "2");
namespaced.sadd("foo", "3");
namespaced.sadd("bar", "2");
namespaced.sadd("bar", "3");
assertEquals(asSet("1", "2", "3"), namespaced.smembers("foo"));
assertEquals(asSet("2", "3"), namespaced.smembers("bar"));
namespaced.smove("foo", "bar", "1");
assertEquals(asSet("2", "3"), namespaced.smembers("foo"));
assertEquals(asSet("1", "2", "3"), namespaced.smembers("bar"));
}
@Test
public void shouldProperlyIntersectThreeSets() {
namespaced.sadd("foo", "1");
namespaced.sadd("foo", "2");
namespaced.sadd("foo", "3");
namespaced.sadd("bar", "2");
namespaced.sadd("bar", "3");
namespaced.sadd("bar", "4");
namespaced.sadd("baz", "3");
assertEquals(asSet("3"), namespaced.sinter("foo", "bar", "baz"));
}
@Test
public void shouldProperlyUnionTwoSets() {
namespaced.sadd("foo", "1");
namespaced.sadd("foo", "2");
namespaced.sadd("bar", "2");
namespaced.sadd("bar", "3");
namespaced.sadd("bar", "4");
assertEquals(asSet("1", "2", "3", "4"), namespaced.sunion("foo", "bar"));
}
@Test
public void shouldProperlyUnionTwoSortedSetsWithOptions() {
namespaced.zadd("sort1", 1, "1");
namespaced.zadd("sort1", 2, "2");
namespaced.zadd("sort2", 2, "2");
namespaced.zadd("sort2", 3, "3");
namespaced.zadd("sort2", 4, "4");
namespaced.zunionstore("union", new ZParams().weights(2, 1), "sort1", "sort2");
assertEquals(asSet("2", "4", "3", "1"), namespaced.zrevrange("union", 0, -1));
}
@Test
public void shouldProperlyUnionTwoSortedSetsWithoutOptions() {
namespaced.zadd("sort1", 1, "1");
namespaced.zadd("sort1", 2, "2");
namespaced.zadd("sort2", 2, "2");
namespaced.zadd("sort2", 3, "3");
namespaced.zadd("sort2", 4, "4");
namespaced.zunionstore("union", "sort1", "sort2");
assertEquals(asSet("4", "2", "3", "1"), namespaced.zrevrange("union", 0, -1));
}
@Test
public void shouldAddNamespaceToSort() {
namespaced.sadd("foo", "1");
namespaced.sadd("foo", "2");
namespaced.set("weight_1", "2");
namespaced.set("weight_2", "1");
namespaced.set("value_1", "a");
namespaced.set("value_2", "b");
assertEquals(asList("1", "2"), namespaced.sort("foo"));
assertEquals(asList("1"), namespaced.sort("foo", new SortingParams().limit(0, 1)));
assertEquals(asList("2", "1"), namespaced.sort("foo", new SortingParams().desc()));
assertEquals(asList("2", "1"), namespaced.sort("foo", new SortingParams().by("weight_*")));
assertEquals(asList("a", "b"), namespaced.sort("foo", new SortingParams().get("value_*")));
namespaced.sort("foo", "result");
assertEquals(asList("1", "2"), namespaced.lrange("result", 0, -1));
}
@Test
public void shouldYieldTheCorrectListOfKeys() {
namespaced.set("foo", "1");
namespaced.set("bar", "2");
namespaced.set("baz", "3");
assertEquals(asSet("bar", "baz", "foo"), namespaced.keys("*"));
}
@Test
public void canChangeItsNamespace() {
assertNull(namespaced.get("foo"));
namespaced.set("foo", "chris");
assertEquals("chris", namespaced.get("foo"));
assertEquals("ns", ((NamespaceJedis)namespaced).getNamespace());
((NamespaceJedis)namespaced).setNamespace("test");
assertEquals("test", ((NamespaceJedis)namespaced).getNamespace());
assertNull(namespaced.get("foo"));
namespaced.set("foo", "chris");
assertEquals("chris", namespaced.get("foo"));
}
@Test
public void poolCanChangeItsNamespace() {
assertNull(namespaced.get("foo"));
namespaced.set("foo", "chris");
assertEquals("chris", namespaced.get("foo"));
assertEquals("ns", ((NamespaceJedis)namespaced).getNamespace());
((NamespaceJedis)namespaced).setNamespace("test");
assertEquals("test", ((NamespaceJedis)namespaced).getNamespace());
assertNull(namespaced.get("foo"));
namespaced.set("foo", "alice");
assertEquals("alice", namespaced.get("foo"));
Jedis secondNamespaced = namespacedPool.getResource();
assertEquals("chris", secondNamespaced.get("foo"));
assertEquals("alice", namespaced.get("foo"));
namespacedPool.returnResource(secondNamespaced);
}
@Test
public void shouldBeAbleToUseANamespaceWithAppend() {
assertNull(namespaced.get("foo"));
namespaced.append("foo", "foo");
namespaced.append("foo", "bar");
assertEquals("foobar", namespaced.get("foo"));
assertEquals("foobar", jedis.get("ns:foo"));
}
@Test
public void shouldBeAbleToUseANamespaceWithIncrDecr() {
assertNull(namespaced.get("foo"));
namespaced.incr("foo");
assertEquals("1", namespaced.get("foo"));
namespaced.incrBy("foo", 3);
assertEquals("4", namespaced.get("foo"));
namespaced.decr("foo");
assertEquals("3", namespaced.get("foo"));
namespaced.decrBy("foo", 3);
assertEquals("0", namespaced.get("foo"));
}
@Test
public void shouldBeAbleToUseANamespaceWithLists() {
assertNull(namespaced.get("foo"));
namespaced.lpushx("foo", "bar");
assertNull(namespaced.get("foo"));
namespaced.lpush("foo", "20");
namespaced.lpush("foo", "10");
namespaced.linsert("foo", AFTER, "20", "40");
namespaced.linsert("foo", BEFORE, "40", "30");
assertEquals(Long.valueOf(4), namespaced.llen("foo"));
assertEquals("10", namespaced.lindex("foo", 0));
assertEquals(asList("20", "30"), namespaced.lrange("foo", 1, 2));
namespaced.lset("foo", 0, "40");
namespaced.lrem("foo", 1, "40");
namespaced.ltrim("foo", 1, 2);
assertEquals(asList("30", "40"), namespaced.lrange("foo", 0, 3));
}
@Test
public void shouldBeAbleToUseANamespaceWithListsPipelined() {
Pipeline pipeline = namespaced.pipelined();
Response<String> response1 = pipeline.get("foo");
pipeline.lpushx("foo", "bar");
Response<String> response2 = pipeline.get("foo");
pipeline.lpush("foo", "20");
pipeline.lpush("foo", "10");
pipeline.linsert("foo", AFTER, "20", "40");
pipeline.linsert("foo", BEFORE, "40", "30");
Response<Long> response3 = pipeline.llen("foo");
Response<String> response4 = pipeline.lindex("foo", 0);
Response<List<String>> response5 = pipeline.lrange("foo", 1, 2);
pipeline.lset("foo", 0, "40");
pipeline.lrem("foo", 1, "40");
pipeline.ltrim("foo", 1, 2);
Response<List<String>> response6 = pipeline.lrange("foo", 0, 3);
pipeline.sync();
assertNull(response1.get());
assertNull(response2.get());
assertEquals(Long.valueOf(4), response3.get());
assertEquals("10", response4.get());
assertEquals(asList("20", "30"), response5.get());
assertEquals(asList("30", "40"), response6.get());
}
@Test
public void canReturnAndCheckoutUsableResource() {
namespaced.set("breadcrumb", "something");
assertEquals("something", jedis.get("ns:breadcrumb"));
namespacedPool.returnResource(namespaced);
namespaced = namespacedPool.getResource();
assertEquals("something", namespaced.get("breadcrumb"));
}
@Test
public void canCheckoutMultipleUsableResource() {
namespaced.set("breadcrumb", "somethingElse");
assertEquals("somethingElse", jedis.get("ns:breadcrumb"));
Jedis other = namespacedPool.getResource();
assertEquals("somethingElse", other.get("breadcrumb"));
namespacedPool.returnResource(other);
}
protected static <T> Set<T> asSet(T... values) {
return new HashSet<T>(Arrays.asList(values));
}
protected static <T> Map<T, T> asMap(T... keyvalues) {
Builder<T, T> builder = ImmutableMap.builder();
for (int i = 0; i < keyvalues.length; i += 2) {
T key = keyvalues[i], value = null;
if (i + 1 < keyvalues.length) {
value = keyvalues[i + 1];
}
builder.put(key, value);
}
return builder.build();
}
}