diff --git a/pom.xml b/pom.xml
index 5f01c037..0af54c16 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,11 @@
2.6.0
test
+
+ org.mockito
+ mockito-all
+ 1.8.5
+
com.google.guava
diff --git a/src/main/java/redis/embedded/AbstractRedisInstance.java b/src/main/java/redis/embedded/AbstractRedisInstance.java
index e410d978..aabce247 100644
--- a/src/main/java/redis/embedded/AbstractRedisInstance.java
+++ b/src/main/java/redis/embedded/AbstractRedisInstance.java
@@ -1,5 +1,7 @@
package redis.embedded;
+import redis.embedded.exceptions.EmbeddedRedisException;
+
import java.io.*;
import java.util.Collections;
import java.util.List;
@@ -9,7 +11,7 @@
/**
* Created by piotrturek on 22/01/15.
*/
-abstract class AbstractRedisInstance implements RedisInstance {
+abstract class AbstractRedisInstance implements Redis {
protected List args = Collections.emptyList();
private volatile boolean active = false;
private Process redisProcess;
@@ -22,14 +24,18 @@ public boolean isActive() {
}
@Override
- public synchronized void start() throws IOException {
+ public synchronized void start() throws EmbeddedRedisException {
if (active) {
- throw new RuntimeException("This redis server instance is already running...");
+ throw new EmbeddedRedisException("This redis server instance is already running...");
+ }
+ try {
+ redisProcess = createRedisProcessBuilder().start();
+ logErrors();
+ awaitRedisServerReady();
+ active = true;
+ } catch (IOException e) {
+ throw new EmbeddedRedisException("Failed to start Reddis instance", e);
}
- redisProcess = createRedisProcessBuilder().start();
- logErrors();
- awaitRedisServerReady();
- active = true;
}
private void logErrors() {
@@ -70,11 +76,19 @@ private ProcessBuilder createRedisProcessBuilder() {
}
@Override
- public synchronized void stop() throws InterruptedException {
+ public synchronized void stop() throws EmbeddedRedisException {
if (active) {
redisProcess.destroy();
- redisProcess.waitFor();
+ tryWaitFor();
active = false;
}
}
+
+ private void tryWaitFor() {
+ try {
+ redisProcess.waitFor();
+ } catch (InterruptedException e) {
+ throw new EmbeddedRedisException("Failed to stop redis instance", e);
+ }
+ }
}
diff --git a/src/main/java/redis/embedded/Redis.java b/src/main/java/redis/embedded/Redis.java
new file mode 100644
index 00000000..9e77a16a
--- /dev/null
+++ b/src/main/java/redis/embedded/Redis.java
@@ -0,0 +1,14 @@
+package redis.embedded;
+
+import redis.embedded.exceptions.EmbeddedRedisException;
+
+/**
+ * Created by piotrturek on 22/01/15.
+ */
+public interface Redis {
+ boolean isActive();
+
+ void start() throws EmbeddedRedisException;
+
+ void stop() throws EmbeddedRedisException;
+}
diff --git a/src/main/java/redis/embedded/RedisCluster.java b/src/main/java/redis/embedded/RedisCluster.java
new file mode 100644
index 00000000..788fdbb3
--- /dev/null
+++ b/src/main/java/redis/embedded/RedisCluster.java
@@ -0,0 +1,36 @@
+package redis.embedded;
+
+import redis.embedded.exceptions.EmbeddedRedisException;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by piotrturek on 22/01/15.
+ */
+public class RedisCluster implements Redis {
+ private final List sentinels = new LinkedList<>();
+ private final List servers = new LinkedList<>();
+
+ public RedisCluster(List sentinels, List servers) {
+ this.servers.addAll(servers);
+ this.sentinels.addAll(sentinels);
+ }
+
+ @Override
+ public boolean isActive() {
+ return sentinels.stream().allMatch(Redis::isActive) && servers.stream().allMatch(Redis::isActive);
+ }
+
+ @Override
+ public void start() throws EmbeddedRedisException {
+ sentinels.parallelStream().forEach(Redis::start);
+ servers.parallelStream().forEach(Redis::start);
+ }
+
+ @Override
+ public void stop() throws EmbeddedRedisException {
+ servers.parallelStream().forEach(Redis::stop);
+ sentinels.parallelStream().forEach(Redis::stop);
+ }
+}
diff --git a/src/main/java/redis/embedded/RedisInstance.java b/src/main/java/redis/embedded/RedisInstance.java
deleted file mode 100644
index 9d1d457b..00000000
--- a/src/main/java/redis/embedded/RedisInstance.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package redis.embedded;
-
-import java.io.IOException;
-
-/**
- * Created by piotrturek on 22/01/15.
- */
-public interface RedisInstance {
- boolean isActive();
-
- void start() throws IOException;
-
- void stop() throws InterruptedException;
-}
diff --git a/src/main/java/redis/embedded/exceptions/EmbeddedRedisException.java b/src/main/java/redis/embedded/exceptions/EmbeddedRedisException.java
new file mode 100644
index 00000000..58dbb822
--- /dev/null
+++ b/src/main/java/redis/embedded/exceptions/EmbeddedRedisException.java
@@ -0,0 +1,14 @@
+package redis.embedded.exceptions;
+
+/**
+ * Created by piotrturek on 22/01/15.
+ */
+public class EmbeddedRedisException extends RuntimeException {
+ public EmbeddedRedisException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public EmbeddedRedisException(String message) {
+ super(message);
+ }
+}
diff --git a/src/test/java/redis/embedded/RedisClusterTest.java b/src/test/java/redis/embedded/RedisClusterTest.java
new file mode 100644
index 00000000..994ecc3f
--- /dev/null
+++ b/src/test/java/redis/embedded/RedisClusterTest.java
@@ -0,0 +1,78 @@
+package redis.embedded;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class RedisClusterTest {
+ private Redis sentinel1;
+ private Redis sentinel2;
+ private Redis master1;
+ private Redis master2;
+
+ private RedisCluster instance;
+
+ @Before
+ public void setUp() throws Exception {
+ sentinel1 = mock(Redis.class);
+ sentinel2 = mock(Redis.class);
+ master1 = mock(Redis.class);
+ master2 = mock(Redis.class);
+ }
+
+
+ @Test
+ public void stopShouldStopEntireCluster() throws Exception {
+ //given
+ final List sentinels = Arrays.asList(sentinel1, sentinel2);
+ final List servers = Arrays.asList(master1, master2);
+ instance = new RedisCluster(sentinels, servers);
+
+ //when
+ instance.stop();
+
+ //then
+ sentinels.stream().forEach(s -> verify(s).stop());
+ servers.stream().forEach(m -> verify(m).stop());
+ }
+
+ @Test
+ public void startShouldStartEntireCluster() throws Exception {
+ //given
+ final List sentinels = Arrays.asList(sentinel1, sentinel2);
+ final List servers = Arrays.asList(master1, master2);
+ instance = new RedisCluster(sentinels, servers);
+
+ //when
+ instance.start();
+
+ //then
+ sentinels.stream().forEach(s -> verify(s).start());
+ servers.stream().forEach(m -> verify(m).start());
+ }
+
+ @Test
+ public void isActiveShouldCheckEntireClusterIfAllActive() throws Exception {
+ //given
+ given(sentinel1.isActive()).willReturn(true);
+ given(sentinel2.isActive()).willReturn(true);
+ given(master1.isActive()).willReturn(true);
+ given(master2.isActive()).willReturn(true);
+ final List sentinels = Arrays.asList(sentinel1, sentinel2);
+ final List servers = Arrays.asList(master1, master2);
+ instance = new RedisCluster(sentinels, servers);
+
+ //when
+ instance.isActive();
+
+ //then
+ sentinels.stream().forEach(s -> verify(s).isActive());
+ servers.stream().forEach(m -> verify(m).isActive());
+ }
+}
\ No newline at end of file