Skip to content

Commit

Permalink
redis cluster builder allows to explicitly set port number of first s…
Browse files Browse the repository at this point in the history
…entinel; cleaning conf of sentinel after builder reset; cleaning conf of server after builder reset; various test scenarios added for redis cluster and its builder; sanity tests for sentinel and sentinel builder; README updated with example of embedded cluster
  • Loading branch information
turu committed Jan 26, 2015
1 parent 5ab458d commit 71a7bfd
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 38 deletions.
58 changes: 24 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,34 @@ embedded-redis

Redis embedded server for Java integration testing


Maven dependency
==============

Currently embedded-redis is available in clojars repository:
```
<repository>
<id>clojars.org</id>
<url>http://clojars.org/repo</url>
</repository>
```

Dependency configuration:
```
<dependency>
<groupId>redis.embedded</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.3</version>
</dependency>
```
More at https://clojars.org/redis.embedded/embedded-redis

Usage example
Usage
==============

Running RedisServer is as simple as:
```
```java
RedisServer redisServer = new RedisServer(6379);
redisServer.start();
// do some work
redisServer.stop();
```

You can also provide RedisServer with your own redis executable to run:
```
```java
RedisServer redisServer = new RedisServer("/path/to/your/redis", 6379);
```

You can also use fluent API to create RedisServer:
```
```java
RedisServer redisServer = RedisServer.builder()
.executable("/path/to/your/redis")
.port(6379)
.slaveOf("locahost", 6378)
.configFile("/path/to/your/redis.conf")
.build();
```

Or even create simple redis.conf file from scratch:
```
```java
RedisServer redisServer = RedisServer.builder()
.executable("/path/to/your/redis")
.port(6379)
Expand All @@ -58,15 +39,23 @@ RedisServer redisServer = RedisServer.builder()
.setting("appendonly no")
.build();
```
A simple redis integration test would look like this:
```

Our Embedded Redis has support for HA Redis clusters with Sentinels and master-slave replication

A simple redis integration test with Redis cluster setup similar to that from production would look like this:
```java
public class SomeIntegrationTestThatRequiresRedis {
private RedisServer redisServer;
private RedisCluster cluster;

@Before
public void setup() throws Exception {
redisServer = new RedisServer(6379); // or new RedisServer("/path/to/your/redis", 6379);
redisServer.start();
//creates a cluster with 3 sentinels, quorum size of 2 and 3 replication groups, each with one master and one slave
cluster = RedisCluster.builder().sentinelCount(3).quorumSize(2)
.replicationGroup("master1", 1)
.replicationGroup("master2", 1)
.replicationGroup("master3", 1)
.build();
cluster.start();
}

@Test
Expand All @@ -76,7 +65,7 @@ public class SomeIntegrationTestThatRequiresRedis {

@After
public void tearDown() throws Exception {
redisServer.stop();
cluster.stop();
}
}
```
Expand All @@ -86,7 +75,8 @@ Redis version
==============

When not provided with the desired redis executable, RedisServer runs os-dependent executable enclosed in jar. Currently is uses:
- Redis 2.6.14 in case of Linux/Unix
- Redis 2.8.19 in case of Linux/Unix
- Redis 2.8.19 in case of OSX
- unofficial Win32/64 port from https://github.com/MSOpenTech/redis (branch 2.6) in case of Windows

However, you should provide RedisServer with redis executable if you need specific version.
5 changes: 5 additions & 0 deletions src/main/java/redis/embedded/RedisClusterBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public RedisClusterBuilder sentinelCount(int sentinelCount) {
return this;
}

public RedisClusterBuilder sentinelStartingPort(int startingPort) {
this.currentSentinelPort = startingPort;
return this;
}

public RedisClusterBuilder quorumSize(int quorumSize) {
this.quorumSize = quorumSize;
return this;
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/redis/embedded/RedisSentinelBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ public RedisSentinelBuilder parallelSyncs(int parallelSyncs) {

public RedisSentinelBuilder configFile(String redisConf) {
if (redisConfigBuilder != null) {
throw new RuntimeException("Redis configuration is already partially build using setting(String) method!");
throw new RedisBuildingException("Redis configuration is already partially build using setting(String) method!");
}
this.sentinelConf = redisConf;
return this;
}

public RedisSentinelBuilder setting(String configLine) {
if (sentinelConf != null) {
throw new RuntimeException("Redis configuration is already set using redis conf file!");
throw new RedisBuildingException("Redis configuration is already set using redis conf file!");
}

if (redisConfigBuilder == null) {
Expand Down Expand Up @@ -123,6 +123,7 @@ private void tryResolveConfAndExec() {

public void reset() {
this.redisConfigBuilder = null;
this.sentinelConf = null;
}

public void addDefaultReplicationGroup() {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/redis/embedded/RedisServerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ public RedisServerBuilder slaveOf(InetSocketAddress slaveOf) {

public RedisServerBuilder configFile(String redisConf) {
if (redisConfigBuilder != null) {
throw new RuntimeException("Redis configuration is already partially build using setting(String) method!");
throw new RedisBuildingException("Redis configuration is already partially build using setting(String) method!");
}
this.redisConf = redisConf;
return this;
}

public RedisServerBuilder setting(String configLine) {
if (redisConf != null) {
throw new RuntimeException("Redis configuration is already set using redis conf file!");
throw new RedisBuildingException("Redis configuration is already set using redis conf file!");
}

if (redisConfigBuilder == null) {
Expand All @@ -82,6 +82,7 @@ public RedisServer build() {
public void reset() {
this.redisConfigBuilder = null;
this.slaveOf = null;
this.redisConf = null;
}

private void tryResolveConfAndExec() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ public class RedisBuildingException extends RuntimeException {
public RedisBuildingException(String message, Throwable cause) {
super(message, cause);
}

public RedisBuildingException(String message) {
super(message);
}
}
130 changes: 130 additions & 0 deletions src/test/java/redis/embedded/RedisClusterTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package redis.embedded;

import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;

import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -75,4 +79,130 @@ public void isActiveShouldCheckEntireClusterIfAllActive() throws Exception {
sentinels.stream().forEach(s -> verify(s).isActive());
servers.stream().forEach(m -> verify(m).isActive());
}

@Test
public void testSimpleOperationsAfterRunWithSingleMasterNoSlavesCluster() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 0).build();
cluster.start();

//when
JedisSentinelPool pool = null;
Jedis jedis = null;
try {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
cluster.stop();
}
}

@Test
public void testSimpleOperationsAfterRunWithSingleMasterAndOneSlave() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 1).build();
cluster.start();

//when
JedisSentinelPool pool = null;
Jedis jedis = null;
try {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
cluster.stop();
}
}

@Test
public void testSimpleOperationsAfterRunWithSingleMasterMultipleSlaves() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 2).build();
cluster.start();

//when
JedisSentinelPool pool = null;
Jedis jedis = null;
try {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
cluster.stop();
}
}

@Test
public void testSimpleOperationsAfterRunWithTwoSentinelsSingleMasterMultipleSlaves() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(2).replicationGroup("ourmaster", 2).build();
cluster.start();

//when
JedisSentinelPool pool = null;
Jedis jedis = null;
try {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379", "localhost:26380"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
cluster.stop();
}
}

@Test
public void testSimpleOperationsAfterRunWithThreeSentinelsThreeMastersOneSlavePerMasterCluster() throws Exception {
//given
final String master1 = "master1";
final String master2 = "master2";
final String master3 = "master3";
final RedisCluster cluster = RedisCluster.builder().sentinelCount(3).quorumSize(2)
.replicationGroup(master1, 1)
.replicationGroup(master2, 1)
.replicationGroup(master3, 1)
.build();
cluster.start();

//when
JedisSentinelPool pool1 = null;
JedisSentinelPool pool2 = null;
JedisSentinelPool pool3 = null;
Jedis jedis1 = null;
Jedis jedis2 = null;
Jedis jedis3 = null;
try {
pool1 = new JedisSentinelPool(master1, Sets.newHashSet("localhost:26379", "localhost:26380", "localhost:26381"));
pool2 = new JedisSentinelPool(master2, Sets.newHashSet("localhost:26379", "localhost:26380", "localhost:26381"));
pool3 = new JedisSentinelPool(master3, Sets.newHashSet("localhost:26379", "localhost:26380", "localhost:26381"));
jedis1 = testPool(pool1);
jedis2 = testPool(pool2);
jedis3 = testPool(pool3);
} finally {
if (jedis1 != null)
pool1.returnResource(jedis1);
if (jedis2 != null)
pool2.returnResource(jedis2);
if (jedis3 != null)
pool3.returnResource(jedis3);
cluster.stop();
}
}

private Jedis testPool(JedisSentinelPool pool) {
Jedis jedis;
jedis = pool.getResource();
jedis.mset("abc", "1", "def", "2");

//then
assertEquals("1", jedis.mget("abc").get(0));
assertEquals("2", jedis.mget("def").get(0));
assertEquals(null, jedis.mget("xyz").get(0));
return jedis;
}
}
47 changes: 47 additions & 0 deletions src/test/java/redis/embedded/RedisSentinelTest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package redis.embedded;

import com.google.common.collect.Sets;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;

public class RedisSentinelTest {
private RedisSentinel sentinel;
private RedisServer server;
Expand All @@ -19,4 +24,46 @@ public void testSimpleRun() throws Exception {
sentinel.stop();
}

@Test
public void shouldAllowSubsequentRuns() throws Exception {
sentinel = RedisSentinel.builder().build();
sentinel.start();
sentinel.stop();

sentinel.start();
sentinel.stop();

sentinel.start();
sentinel.stop();
}

@Test
public void testSimpleOperationsAfterRun() throws Exception {
//given
server = new RedisServer();
sentinel = RedisSentinel.builder().build();
server.start();
sentinel.start();
TimeUnit.SECONDS.sleep(1);

//when
JedisSentinelPool pool = null;
Jedis jedis = null;
try {
pool = new JedisSentinelPool("mymaster", Sets.newHashSet("localhost:26379"));
jedis = pool.getResource();
jedis.mset("abc", "1", "def", "2");

//then
assertEquals("1", jedis.mget("abc").get(0));
assertEquals("2", jedis.mget("def").get(0));
assertEquals(null, jedis.mget("xyz").get(0));
} finally {
if (jedis != null)
pool.returnResource(jedis);
sentinel.stop();
server.stop();
}
}

}

0 comments on commit 71a7bfd

Please sign in to comment.