From 0e18dd96f55dac5893c0bf6d979c849457a78eee Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Tue, 15 Mar 2016 00:21:44 +0000
Subject: [PATCH 1/6] Make RedisRunner Accepts redis-server cli options

WIP
---
 src/test/java/org/redisson/RedisRunner.java | 44 ++++++++++++++++++++-
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/src/test/java/org/redisson/RedisRunner.java b/src/test/java/org/redisson/RedisRunner.java
index dfdf7bdc6..0be95b479 100644
--- a/src/test/java/org/redisson/RedisRunner.java
+++ b/src/test/java/org/redisson/RedisRunner.java
@@ -3,20 +3,60 @@ package org.redisson;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
 
 public class RedisRunner {
 
+    
     private static final String redisFolder = "C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\";
+    private static final String redisBinary = redisFolder + "redis-server.exe";
+    
+    private final List<String> options = new ArrayList<>();
 
-    public static Process runRedis(String configPath) throws IOException, InterruptedException {
+    {
+        options.add(Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary));
+    }
+    
+    /**
+     * To change the <b>redisBinary</b> system property for running the test,
+     * use <i>argLine</i> option from surefire plugin:
+     *
+     * $ mvn -DargLine="-DredisBinary=`which redis-server`" -Punit-test clean \
+     * verify
+     *
+     * @param configPath
+     * @return Process running redis instance
+     * @throws IOException
+     * @throws InterruptedException
+     * @see
+     * <a href="http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#argLine">
+     * http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#argLine</a>
+     */
+    public static Process runRedisWithConfigFile(String configPath) throws IOException, InterruptedException {
         URL resource = RedisRunner.class.getResource(configPath);
 
-        ProcessBuilder master = new ProcessBuilder(redisFolder + "redis-server.exe", resource.getFile().substring(1));
+        ProcessBuilder master = new ProcessBuilder(
+                Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary),
+                resource.getFile().substring(1));
         master.directory(new File(redisFolder));
         Process p = master.start();
         Thread.sleep(1000);
         return p;
     }
 
+    public RedisRunner withPort(int port) {
+        this.options.add("--port " + port);
+        return this;
+    }
+    
+    public Process run() throws IOException, InterruptedException {
+        ProcessBuilder master = new ProcessBuilder(options);
+        master.directory(new File(redisBinary).getParentFile());
+        Process p = master.start();
+        Thread.sleep(1000);
+        return p;
+    }
 
 }

From 5b1818516b667c234002faeb5a97bd42fc768064 Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Tue, 15 Mar 2016 23:12:33 +0000
Subject: [PATCH 2/6] added all the redis v3.0.7 config options as enum type

---
 src/test/java/org/redisson/RedisRunner.java | 169 +++++++++++++++++++-
 1 file changed, 162 insertions(+), 7 deletions(-)

diff --git a/src/test/java/org/redisson/RedisRunner.java b/src/test/java/org/redisson/RedisRunner.java
index 0be95b479..8d59e57de 100644
--- a/src/test/java/org/redisson/RedisRunner.java
+++ b/src/test/java/org/redisson/RedisRunner.java
@@ -3,20 +3,148 @@ package org.redisson;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 public class RedisRunner {
 
+    enum OPTIONS {
+        BINARY_PATH,
+        DAEMONIZE,
+        PIDFILE,
+        PORT,
+        TCP_BACKLOG,
+        BIND,
+        UNIXSOCKET,
+        UNIXSOCKETPERM,
+        TIMEOUT,
+        TCP_KEEPALIVE,
+        LOGLEVEL,
+        LOGFILE,
+        SYSLOG_ENABLED,
+        SYSLOG_IDENT,
+        SYSLOG_FACILITY,
+        DATABASES,
+        SAVE,
+        STOP_WRITES_ON_BGSAVE_ERROR,
+        RDBCOMPRESSION,
+        RDBCHECKSUM,
+        DBFILENAME,
+        DIR,
+        SLAVEOF,
+        MASTERAUTH,
+        SLAVE_SERVE_STALE_DATA,
+        SLAVE_READ_ONLY,
+        REPL_DISKLESS_SYNC,
+        REPL_DISKLESS_SYNC_DELAY,
+        REPL_PING_SLAVE_PERIOD,
+        REPL_TIMEOUT,
+        REPL_DISABLE_TCP_NODELAY,
+        REPL_BACKLOG_SIZE,
+        REPL_BACKLOG_TTL,
+        SLAVE_PRIORITY,
+        MIN_SLAVES_TO_WRITE,
+        MIN_SLAVES_MAX_LAG,
+        REQUREPASS,
+        RENAME_COMMAND,
+        MAXCLIENTS,
+        MAXMEMORY,
+        MAXMEMORY_POLICY,
+        MAXMEMORY_SAMPLE,
+        APPEND_ONLY,
+        APPENDFILENAME,
+        APPENDFSYNC,
+        NO_APPENDFSYNC_ON_REWRITE,
+        AUTO_AOF_REWRITE_PERCENTAGE,
+        AUTO_AOF_REWRITE_MIN_SIZE,
+        AOF_LOAD_TRUNCATED,
+        LUA_TIME_LIMIT,
+        CLUSTER_ENABLED,
+        CLUSTER_CONFIG_FILE,
+        CLUSTER_NODE_TIMEOUT,
+        CLUSTER_SLAVE_VALIDITY_FACTOR,
+        CLUSTER_MIGRATION_BARRIER,
+        CLUSTER_REQUIRE_FULL_COVERAGE,
+        SLOWLOG_LOG_SLOWER_THAN,
+        SLOWLOG_MAX_LEN,
+        LATENCY_MONITOR_THRESHOLD,
+        NOFITY_KEYSPACE_EVENTS,
+        HASH_MAX_ZIPLIST_ENTRIES,
+        HASH_MAX_ZIPLIST_VALUE,
+        LIST_MAX_ZIPLIST_ENTRIES,
+        LIST_MAX_ZIPLIST_VALUE,
+        SET_MAX_INTSET_ENTRIES,
+        ZSET_MAX_ZIPLIST_ENTRIES,
+        ZSET_MAX_ZIPLIST_VALUE,
+        HLL_SPARSE_MAX_BYTES,
+        ACTIVEREHASHING,
+        CLIENT_OUTPUT_BUFFER_LIMIT,//MULTI
+        HZ,
+        AOF_REWRITE_INCREMENTAL_FSYNC
+    }
+    
+    enum LOGLEVEL_OPTIONS {
+        DEBUG,
+        VERBOSE,
+        NOTICE,
+        WARNING
+    }
+    
+    enum SYSLOG_FACILITY_OPTIONS {
+        USER,
+        LOCAL0,
+        LOCAL1,
+        LOCAL2,
+        LOCAL3,
+        LOCAL4,
+        LOCAL5,
+        LOCAL6,
+        LOCAL7
+    }
+    
+    enum MAX_MEMORY_POLICY_OPTIONS {
+        VOLATILE_LRU,
+        ALLKEYS_LRU,
+        VOLATILE_RANDOM,
+        ALLKEYS_RANDOM,
+        VOLATILE_TTL,
+        NOEVICTION
+    }
     
+    enum APPEND_FSYNC_MODE_OPTIONS {
+        ALWAYS,
+        EVERYSEC,
+        NO
+    }
+    
+    enum KEYSPACE_EVENTS_OPTIONS {
+        K,
+        E,
+        g,
+        $,
+        l,
+        s,
+        h,
+        z,
+        x,
+        e,
+        A
+    }
+    
+    enum CLIENT_CLASS_OPTIONS {
+        NORMAL,
+        SLAVE,
+        PUBSUB
+    }
     private static final String redisFolder = "C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\";
     private static final String redisBinary = redisFolder + "redis-server.exe";
     
-    private final List<String> options = new ArrayList<>();
+    private final LinkedHashMap<OPTIONS, String> options = new LinkedHashMap<>();
 
     {
-        options.add(Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary));
+        options.put(OPTIONS.BINARY_PATH, Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary));
     }
     
     /**
@@ -46,13 +174,40 @@ public class RedisRunner {
         return p;
     }
 
-    public RedisRunner withPort(int port) {
-        this.options.add("--port " + port);
+    private void addConfigOption(OPTIONS option, String... args) {
+        StringBuilder sb = new StringBuilder("--");
+        sb.append(option.toString().replaceAll("_", "-").toLowerCase());
+        sb.append(" ");
+        sb.append(Arrays.stream(args).collect(Collectors.joining(" ")));
+        this.options.put(option, sb.toString());
+    }
+    
+    private String convertBoolean(boolean b) {
+        return b ? "yes" : "no";
+    }
+    
+    public RedisRunner daemonize(boolean daemonize) {
+        addConfigOption(OPTIONS.DAEMONIZE, convertBoolean(daemonize));
+        return this;
+    }
+    
+    public RedisRunner pidfile(String pidfile) {
+        addConfigOption(OPTIONS.PIDFILE, pidfile);
+        return this;
+    }
+    
+    public RedisRunner port(int port) {
+        addConfigOption(OPTIONS.PORT, port + "");
+        return this;
+    }
+    
+    public RedisRunner tcpBacklog(int tcpBacklog) {
+        addConfigOption(OPTIONS.TCP_BACKLOG, "" + tcpBacklog);
         return this;
     }
     
     public Process run() throws IOException, InterruptedException {
-        ProcessBuilder master = new ProcessBuilder(options);
+        ProcessBuilder master = new ProcessBuilder(options.values().stream().collect(Collectors.joining(" ")));
         master.directory(new File(redisBinary).getParentFile());
         Process p = master.start();
         Thread.sleep(1000);

From 76c5ece35abc4a50b0a5e878c0576152a1ad7e89 Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Tue, 15 Mar 2016 23:13:04 +0000
Subject: [PATCH 3/6] changed existing test code to use runRedisWithConfigFile
 method

---
 src/test/java/org/redisson/RedissonMultiLockTest.java | 6 +++---
 src/test/java/org/redisson/RedissonTest.java          | 8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/test/java/org/redisson/RedissonMultiLockTest.java b/src/test/java/org/redisson/RedissonMultiLockTest.java
index d7a2e2a2e..22e0cd1e7 100644
--- a/src/test/java/org/redisson/RedissonMultiLockTest.java
+++ b/src/test/java/org/redisson/RedissonMultiLockTest.java
@@ -17,9 +17,9 @@ public class RedissonMultiLockTest {
 
     @Test
     public void test() throws IOException, InterruptedException {
-        Process redis1 = RedisRunner.runRedis("/redis_multiLock_test_instance1.conf");
-        Process redis2 = RedisRunner.runRedis("/redis_multiLock_test_instance2.conf");
-        Process redis3 = RedisRunner.runRedis("/redis_multiLock_test_instance3.conf");
+        Process redis1 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance1.conf");
+        Process redis2 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance2.conf");
+        Process redis3 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance3.conf");
 
         NioEventLoopGroup group = new NioEventLoopGroup();
         Config config1 = new Config();
diff --git a/src/test/java/org/redisson/RedissonTest.java b/src/test/java/org/redisson/RedissonTest.java
index 449669448..73588a006 100644
--- a/src/test/java/org/redisson/RedissonTest.java
+++ b/src/test/java/org/redisson/RedissonTest.java
@@ -61,7 +61,7 @@ public class RedissonTest {
     
     @Test(expected = RedisOutOfMemoryException.class)
     public void testMemoryScript() throws IOException, InterruptedException {
-        Process p = RedisRunner.runRedis("/redis_oom_test.conf");
+        Process p = RedisRunner.runRedisWithConfigFile("/redis_oom_test.conf");
 
         Config config = new Config();
         config.useSingleServer().setAddress("127.0.0.1:6319").setTimeout(100000);
@@ -78,7 +78,7 @@ public class RedissonTest {
 
     @Test(expected = RedisOutOfMemoryException.class)
     public void testMemoryCommand() throws IOException, InterruptedException {
-        Process p = RedisRunner.runRedis("/redis_oom_test.conf");
+        Process p = RedisRunner.runRedisWithConfigFile("/redis_oom_test.conf");
 
         Config config = new Config();
         config.useSingleServer().setAddress("127.0.0.1:6319").setTimeout(100000);
@@ -97,7 +97,7 @@ public class RedissonTest {
     @Test
     public void testConnectionListener() throws IOException, InterruptedException, TimeoutException {
 
-        Process p = RedisRunner.runRedis("/redis_connectionListener_test.conf");
+        Process p = RedisRunner.runRedisWithConfigFile("/redis_connectionListener_test.conf");
 
         final AtomicInteger connectCounter = new AtomicInteger();
         final AtomicInteger disconnectCounter = new AtomicInteger();
@@ -134,7 +134,7 @@ public class RedissonTest {
         } catch (Exception e) {
         }
 
-        p = RedisRunner.runRedis("/redis_connectionListener_test.conf");
+        p = RedisRunner.runRedisWithConfigFile("/redis_connectionListener_test.conf");
 
         r.getBucket("1").get();
 

From c1695e0ac8734353dc8130bb43c87b115c7f1ff9 Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Thu, 17 Mar 2016 00:09:57 +0000
Subject: [PATCH 4/6] WIP update

---
 src/test/java/org/redisson/RedisRunner.java | 128 ++++++++++++++------
 1 file changed, 91 insertions(+), 37 deletions(-)

diff --git a/src/test/java/org/redisson/RedisRunner.java b/src/test/java/org/redisson/RedisRunner.java
index 8d59e57de..d4c4db1b6 100644
--- a/src/test/java/org/redisson/RedisRunner.java
+++ b/src/test/java/org/redisson/RedisRunner.java
@@ -10,13 +10,14 @@ import java.util.stream.Collectors;
 
 public class RedisRunner {
 
-    enum OPTIONS {
+    public enum OPTIONS {
+
         BINARY_PATH,
         DAEMONIZE,
         PIDFILE,
         PORT,
         TCP_BACKLOG,
-        BIND,
+        BIND(true),
         UNIXSOCKET,
         UNIXSOCKETPERM,
         TIMEOUT,
@@ -27,7 +28,7 @@ public class RedisRunner {
         SYSLOG_IDENT,
         SYSLOG_FACILITY,
         DATABASES,
-        SAVE,
+        SAVE(true),
         STOP_WRITES_ON_BGSAVE_ERROR,
         RDBCOMPRESSION,
         RDBCHECKSUM,
@@ -48,7 +49,7 @@ public class RedisRunner {
         MIN_SLAVES_TO_WRITE,
         MIN_SLAVES_MAX_LAG,
         REQUREPASS,
-        RENAME_COMMAND,
+        RENAME_COMMAND(true),
         MAXCLIENTS,
         MAXMEMORY,
         MAXMEMORY_POLICY,
@@ -80,19 +81,37 @@ public class RedisRunner {
         ZSET_MAX_ZIPLIST_VALUE,
         HLL_SPARSE_MAX_BYTES,
         ACTIVEREHASHING,
-        CLIENT_OUTPUT_BUFFER_LIMIT,//MULTI
+        CLIENT_OUTPUT_BUFFER_LIMIT$NORMAL,
+        CLIENT_OUTPUT_BUFFER_LIMIT$SLAVE,
+        CLIENT_OUTPUT_BUFFER_LIMIT$PUBSUB,
         HZ,
-        AOF_REWRITE_INCREMENTAL_FSYNC
+        AOF_REWRITE_INCREMENTAL_FSYNC;
+
+        private final boolean allowMutiple;
+
+        private OPTIONS() {
+            this.allowMutiple = false;
+        }
+
+        private OPTIONS(boolean allowMutiple) {
+            this.allowMutiple = allowMutiple;
+        }
+
+        public boolean isAllowMultiple() {
+            return allowMutiple;
+        }
     }
-    
-    enum LOGLEVEL_OPTIONS {
+
+    public enum LOGLEVEL_OPTIONS {
+
         DEBUG,
         VERBOSE,
         NOTICE,
         WARNING
     }
-    
-    enum SYSLOG_FACILITY_OPTIONS {
+
+    public enum SYSLOG_FACILITY_OPTIONS {
+
         USER,
         LOCAL0,
         LOCAL1,
@@ -103,8 +122,9 @@ public class RedisRunner {
         LOCAL6,
         LOCAL7
     }
-    
-    enum MAX_MEMORY_POLICY_OPTIONS {
+
+    public enum MAX_MEMORY_POLICY_OPTIONS {
+
         VOLATILE_LRU,
         ALLKEYS_LRU,
         VOLATILE_RANDOM,
@@ -112,14 +132,16 @@ public class RedisRunner {
         VOLATILE_TTL,
         NOEVICTION
     }
-    
-    enum APPEND_FSYNC_MODE_OPTIONS {
+
+    public enum APPEND_FSYNC_MODE_OPTIONS {
+
         ALWAYS,
         EVERYSEC,
         NO
     }
-    
-    enum KEYSPACE_EVENTS_OPTIONS {
+
+    public enum KEYSPACE_EVENTS_OPTIONS {
+
         K,
         E,
         g,
@@ -132,21 +154,18 @@ public class RedisRunner {
         e,
         A
     }
-    
-    enum CLIENT_CLASS_OPTIONS {
-        NORMAL,
-        SLAVE,
-        PUBSUB
-    }
+
     private static final String redisFolder = "C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\";
     private static final String redisBinary = redisFolder + "redis-server.exe";
-    
+
     private final LinkedHashMap<OPTIONS, String> options = new LinkedHashMap<>();
 
     {
-        options.put(OPTIONS.BINARY_PATH, Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary));
+        options.put(OPTIONS.BINARY_PATH,
+                Optional.ofNullable(System.getProperty("redisBinary"))
+                .orElse(redisBinary));
     }
-    
+
     /**
      * To change the <b>redisBinary</b> system property for running the test,
      * use <i>argLine</i> option from surefire plugin:
@@ -166,7 +185,8 @@ public class RedisRunner {
         URL resource = RedisRunner.class.getResource(configPath);
 
         ProcessBuilder master = new ProcessBuilder(
-                Optional.ofNullable(System.getProperty("redisBinary")).orElse(redisBinary),
+                Optional.ofNullable(System.getProperty("redisBinary"))
+                .orElse(redisBinary),
                 resource.getFile().substring(1));
         master.directory(new File(redisFolder));
         Process p = master.start();
@@ -175,39 +195,73 @@ public class RedisRunner {
     }
 
     private void addConfigOption(OPTIONS option, String... args) {
-        StringBuilder sb = new StringBuilder("--");
-        sb.append(option.toString().replaceAll("_", "-").toLowerCase());
-        sb.append(" ");
-        sb.append(Arrays.stream(args).collect(Collectors.joining(" ")));
-        this.options.put(option, sb.toString());
+        StringBuilder sb = new StringBuilder(" --")
+                .append(option.toString()
+                        .replaceAll("_", "-")
+                        .replaceAll("\\$", " ")
+                        .toLowerCase())
+                .append(" ")
+                .append(Arrays.stream(args)
+                        .collect(Collectors.joining(" ")));
+        this.options.put(option, 
+                option.isAllowMultiple()
+                        ? sb.insert(0, this.options.getOrDefault(option, "")).toString()
+                        : sb.toString());
     }
-    
+
     private String convertBoolean(boolean b) {
         return b ? "yes" : "no";
     }
-    
+
     public RedisRunner daemonize(boolean daemonize) {
         addConfigOption(OPTIONS.DAEMONIZE, convertBoolean(daemonize));
         return this;
     }
-    
+
     public RedisRunner pidfile(String pidfile) {
         addConfigOption(OPTIONS.PIDFILE, pidfile);
         return this;
     }
-    
+
     public RedisRunner port(int port) {
         addConfigOption(OPTIONS.PORT, port + "");
         return this;
     }
-    
+
     public RedisRunner tcpBacklog(int tcpBacklog) {
         addConfigOption(OPTIONS.TCP_BACKLOG, "" + tcpBacklog);
         return this;
     }
+
+    public RedisRunner bind(String bind) {
+        addConfigOption(OPTIONS.BIND, bind);
+        return this;
+    }
+
+    public RedisRunner timeout(long timeout) {
+        addConfigOption(OPTIONS.TIMEOUT, "" + timeout);
+        return this;
+    }
+
+    public RedisRunner tcpKeepalive(long tcpKeepalive) {
+        addConfigOption(OPTIONS.TCP_KEEPALIVE, "" + tcpKeepalive);
+        return this;
+    }
     
+    public RedisRunner loglevel(LOGLEVEL_OPTIONS loglevel) {
+        addConfigOption(OPTIONS.LOGLEVEL, loglevel.toString());
+        return this;
+    }
+    
+    public RedisRunner logfile(String logfile) {
+        addConfigOption(OPTIONS.LOGLEVEL, logfile);
+        return this;
+    }
+
     public Process run() throws IOException, InterruptedException {
-        ProcessBuilder master = new ProcessBuilder(options.values().stream().collect(Collectors.joining(" ")));
+        ProcessBuilder master = new ProcessBuilder(
+                options.values().stream()
+                .collect(Collectors.joining()));
         master.directory(new File(redisBinary).getParentFile());
         Process p = master.start();
         Thread.sleep(1000);

From 6ef404b2782ee6a1779ef5ab3e6045d4277ec81b Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Thu, 17 Mar 2016 00:13:55 +0000
Subject: [PATCH 5/6] WIP update

---
 src/test/java/org/redisson/RedisRunner.java | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/test/java/org/redisson/RedisRunner.java b/src/test/java/org/redisson/RedisRunner.java
index d4c4db1b6..f04506021 100644
--- a/src/test/java/org/redisson/RedisRunner.java
+++ b/src/test/java/org/redisson/RedisRunner.java
@@ -238,6 +238,16 @@ public class RedisRunner {
         return this;
     }
 
+    public RedisRunner unixsocket(String unixsocket) {
+        addConfigOption(OPTIONS.UNIXSOCKET, unixsocket);
+        return this;
+    }
+
+    public RedisRunner unixsocketperm(String unixsocketperm) {
+        addConfigOption(OPTIONS.UNIXSOCKETPERM, unixsocketperm);
+        return this;
+    }
+
     public RedisRunner timeout(long timeout) {
         addConfigOption(OPTIONS.TIMEOUT, "" + timeout);
         return this;

From 4caa8f48294588a5fd3941c2192eb5d4a5ee1785 Mon Sep 17 00:00:00 2001
From: jackygurui <jackygurui@gmail.com>
Date: Fri, 18 Mar 2016 01:40:26 +0000
Subject: [PATCH 6/6] Completed RedisRunner mods

* RedisRunner now able to launch redis-server using command line
options.
* Added RedisProcess class which wraps Process class and ensures
unified exit code value in both windows and Mac/Unix/Linux.
* Removed argLine configuration from surefire plugin in pom.xml because
it shadows the command line options.
* Changed test files to launch redis-server programmatically.
---
 pom.xml                                       |   3 -
 src/test/java/org/redisson/RedisRunner.java   | 441 ++++++++++++++++--
 .../org/redisson/RedissonMultiLockTest.java   |  35 +-
 src/test/java/org/redisson/RedissonTest.java  |  31 +-
 4 files changed, 444 insertions(+), 66 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2411aa90c..8907f379a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -351,9 +351,6 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>2.16</version>
-                <configuration>
-                    <argLine>-Dfile.encoding=utf-8</argLine>
-                </configuration>
             </plugin>
 
             <plugin>
diff --git a/src/test/java/org/redisson/RedisRunner.java b/src/test/java/org/redisson/RedisRunner.java
index f04506021..54a152693 100644
--- a/src/test/java/org/redisson/RedisRunner.java
+++ b/src/test/java/org/redisson/RedisRunner.java
@@ -1,16 +1,24 @@
 package org.redisson;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Inet4Address;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
 public class RedisRunner {
 
-    public enum OPTIONS {
+    public enum REDIS_OPTIONS {
 
         BINARY_PATH,
         DAEMONIZE,
@@ -54,7 +62,7 @@ public class RedisRunner {
         MAXMEMORY,
         MAXMEMORY_POLICY,
         MAXMEMORY_SAMPLE,
-        APPEND_ONLY,
+        APPENDONLY,
         APPENDFILENAME,
         APPENDFSYNC,
         NO_APPENDFSYNC_ON_REWRITE,
@@ -89,11 +97,11 @@ public class RedisRunner {
 
         private final boolean allowMutiple;
 
-        private OPTIONS() {
+        private REDIS_OPTIONS() {
             this.allowMutiple = false;
         }
 
-        private OPTIONS(boolean allowMutiple) {
+        private REDIS_OPTIONS(boolean allowMutiple) {
             this.allowMutiple = allowMutiple;
         }
 
@@ -155,15 +163,17 @@ public class RedisRunner {
         A
     }
 
-    private static final String redisFolder = "C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\";
-    private static final String redisBinary = redisFolder + "redis-server.exe";
+    private static final String redisBinary;
 
-    private final LinkedHashMap<OPTIONS, String> options = new LinkedHashMap<>();
+    private final LinkedHashMap<REDIS_OPTIONS, String> options = new LinkedHashMap<>();
+
+    static {
+        redisBinary = Optional.ofNullable(System.getProperty("redisBinary"))
+                .orElse("C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\redis-server.exe");
+    }
 
     {
-        options.put(OPTIONS.BINARY_PATH,
-                Optional.ofNullable(System.getProperty("redisBinary"))
-                .orElse(redisBinary));
+        this.options.put(REDIS_OPTIONS.BINARY_PATH, redisBinary);
     }
 
     /**
@@ -181,21 +191,40 @@ public class RedisRunner {
      * <a href="http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#argLine">
      * http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#argLine</a>
      */
-    public static Process runRedisWithConfigFile(String configPath) throws IOException, InterruptedException {
+    public static RedisProcess runRedisWithConfigFile(String configPath) throws IOException, InterruptedException {
         URL resource = RedisRunner.class.getResource(configPath);
+        return runWithOptions(redisBinary, resource.getFile());
+    }
 
-        ProcessBuilder master = new ProcessBuilder(
-                Optional.ofNullable(System.getProperty("redisBinary"))
-                .orElse(redisBinary),
-                resource.getFile().substring(1));
-        master.directory(new File(redisFolder));
+    private static RedisProcess runWithOptions(String... options) throws IOException, InterruptedException {
+        System.out.println("REDIS LAUNCH OPTIONS: " + Arrays.toString(options));
+        ProcessBuilder master = new ProcessBuilder(options)
+                .redirectErrorStream(true)
+                .directory(new File(redisBinary).getParentFile());
         Process p = master.start();
+        new Thread(() -> {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+            String line;
+            try {
+                while (p.isAlive() && (line = reader.readLine()) != null) {
+                    System.out.println("REDIS PROCESS: " + line);
+                }
+            } catch (IOException ex) {
+                System.out.println("Exception: " + ex.getLocalizedMessage());
+            }
+        }).start();
         Thread.sleep(1000);
-        return p;
+        return new RedisProcess(p);
+    }
+
+    
+    
+    public RedisProcess run() throws IOException, InterruptedException {
+        return runWithOptions(options.values().toArray(new String[0]));
     }
 
-    private void addConfigOption(OPTIONS option, String... args) {
-        StringBuilder sb = new StringBuilder(" --")
+    private void addConfigOption(REDIS_OPTIONS option, String... args) {
+        StringBuilder sb = new StringBuilder("--")
                 .append(option.toString()
                         .replaceAll("_", "-")
                         .replaceAll("\\$", " ")
@@ -203,7 +232,7 @@ public class RedisRunner {
                 .append(" ")
                 .append(Arrays.stream(args)
                         .collect(Collectors.joining(" ")));
-        this.options.put(option, 
+        this.options.put(option,
                 option.isAllowMultiple()
                         ? sb.insert(0, this.options.getOrDefault(option, "")).toString()
                         : sb.toString());
@@ -214,68 +243,394 @@ public class RedisRunner {
     }
 
     public RedisRunner daemonize(boolean daemonize) {
-        addConfigOption(OPTIONS.DAEMONIZE, convertBoolean(daemonize));
+        addConfigOption(REDIS_OPTIONS.DAEMONIZE, convertBoolean(daemonize));
         return this;
     }
 
     public RedisRunner pidfile(String pidfile) {
-        addConfigOption(OPTIONS.PIDFILE, pidfile);
+        addConfigOption(REDIS_OPTIONS.PIDFILE, pidfile);
         return this;
     }
 
     public RedisRunner port(int port) {
-        addConfigOption(OPTIONS.PORT, port + "");
+        addConfigOption(REDIS_OPTIONS.PORT, "" + port);
         return this;
     }
 
-    public RedisRunner tcpBacklog(int tcpBacklog) {
-        addConfigOption(OPTIONS.TCP_BACKLOG, "" + tcpBacklog);
+    public RedisRunner tcpBacklog(long tcpBacklog) {
+        addConfigOption(REDIS_OPTIONS.TCP_BACKLOG, "" + tcpBacklog);
         return this;
     }
 
     public RedisRunner bind(String bind) {
-        addConfigOption(OPTIONS.BIND, bind);
+        addConfigOption(REDIS_OPTIONS.BIND, bind);
         return this;
     }
 
     public RedisRunner unixsocket(String unixsocket) {
-        addConfigOption(OPTIONS.UNIXSOCKET, unixsocket);
+        addConfigOption(REDIS_OPTIONS.UNIXSOCKET, unixsocket);
         return this;
     }
 
-    public RedisRunner unixsocketperm(String unixsocketperm) {
-        addConfigOption(OPTIONS.UNIXSOCKETPERM, unixsocketperm);
+    public RedisRunner unixsocketperm(int unixsocketperm) {
+        addConfigOption(REDIS_OPTIONS.UNIXSOCKETPERM, "" + unixsocketperm);
         return this;
     }
 
     public RedisRunner timeout(long timeout) {
-        addConfigOption(OPTIONS.TIMEOUT, "" + timeout);
+        addConfigOption(REDIS_OPTIONS.TIMEOUT, "" + timeout);
         return this;
     }
 
     public RedisRunner tcpKeepalive(long tcpKeepalive) {
-        addConfigOption(OPTIONS.TCP_KEEPALIVE, "" + tcpKeepalive);
+        addConfigOption(REDIS_OPTIONS.TCP_KEEPALIVE, "" + tcpKeepalive);
         return this;
     }
-    
+
     public RedisRunner loglevel(LOGLEVEL_OPTIONS loglevel) {
-        addConfigOption(OPTIONS.LOGLEVEL, loglevel.toString());
+        addConfigOption(REDIS_OPTIONS.LOGLEVEL, loglevel.toString());
         return this;
     }
-    
+
     public RedisRunner logfile(String logfile) {
-        addConfigOption(OPTIONS.LOGLEVEL, logfile);
+        addConfigOption(REDIS_OPTIONS.LOGLEVEL, logfile);
         return this;
     }
 
-    public Process run() throws IOException, InterruptedException {
-        ProcessBuilder master = new ProcessBuilder(
-                options.values().stream()
-                .collect(Collectors.joining()));
-        master.directory(new File(redisBinary).getParentFile());
-        Process p = master.start();
-        Thread.sleep(1000);
-        return p;
+    public RedisRunner syslogEnabled(boolean syslogEnabled) {
+        addConfigOption(REDIS_OPTIONS.SYSLOG_ENABLED, convertBoolean(syslogEnabled));
+        return this;
+    }
+
+    public RedisRunner syslogIdent(String syslogIdent) {
+        addConfigOption(REDIS_OPTIONS.SYSLOG_IDENT, syslogIdent);
+        return this;
+    }
+
+    public RedisRunner syslogFacility(SYSLOG_FACILITY_OPTIONS syslogFacility) {
+        addConfigOption(REDIS_OPTIONS.SYSLOG_IDENT, syslogFacility.toString());
+        return this;
+    }
+
+    public RedisRunner databases(int databases) {
+        addConfigOption(REDIS_OPTIONS.DATABASES, "" + databases);
+        return this;
+    }
+
+    public RedisRunner save(long seconds, long changes) {
+        addConfigOption(REDIS_OPTIONS.SAVE, "" + seconds, "" + changes);
+        return this;
+    }
+
+    public RedisRunner stopWritesOnBgsaveError(boolean stopWritesOnBgsaveError) {
+        addConfigOption(REDIS_OPTIONS.STOP_WRITES_ON_BGSAVE_ERROR, convertBoolean(stopWritesOnBgsaveError));
+        return this;
+    }
+
+    public RedisRunner rdbcompression(boolean rdbcompression) {
+        addConfigOption(REDIS_OPTIONS.RDBCOMPRESSION, convertBoolean(rdbcompression));
+        return this;
+    }
+
+    public RedisRunner rdbchecksum(boolean rdbchecksum) {
+        addConfigOption(REDIS_OPTIONS.RDBCHECKSUM, convertBoolean(rdbchecksum));
+        return this;
+    }
+
+    public RedisRunner dbfilename(String dbfilename) {
+        addConfigOption(REDIS_OPTIONS.DBFILENAME, dbfilename);
+        return this;
+    }
+
+    public RedisRunner dir(String dir) {
+        addConfigOption(REDIS_OPTIONS.DIR, dir);
+        return this;
+    }
+
+    public RedisRunner slaveof(Inet4Address masterip, int port) {
+        addConfigOption(REDIS_OPTIONS.SLAVEOF, masterip.getHostAddress(), "" + port);
+        return this;
+    }
+
+    public RedisRunner masterauth(String masterauth) {
+        addConfigOption(REDIS_OPTIONS.MASTERAUTH, masterauth);
+        return this;
+    }
+
+    public RedisRunner slaveServeStaleData(boolean slaveServeStaleData) {
+        addConfigOption(REDIS_OPTIONS.SLAVE_SERVE_STALE_DATA, convertBoolean(slaveServeStaleData));
+        return this;
+    }
+
+    public RedisRunner slaveReadOnly(boolean slaveReadOnly) {
+        addConfigOption(REDIS_OPTIONS.SLAVE_READ_ONLY, convertBoolean(slaveReadOnly));
+        return this;
+    }
+
+    public RedisRunner replDisklessSync(boolean replDisklessSync) {
+        addConfigOption(REDIS_OPTIONS.REPL_DISKLESS_SYNC, convertBoolean(replDisklessSync));
+        return this;
+    }
+
+    public RedisRunner replDisklessSyncDelay(long replDisklessSyncDelay) {
+        addConfigOption(REDIS_OPTIONS.REPL_DISKLESS_SYNC_DELAY, "" + replDisklessSyncDelay);
+        return this;
+    }
+
+    public RedisRunner replPingSlavePeriod(long replPingSlavePeriod) {
+        addConfigOption(REDIS_OPTIONS.REPL_PING_SLAVE_PERIOD, "" + replPingSlavePeriod);
+        return this;
+    }
+
+    public RedisRunner replTimeout(long replTimeout) {
+        addConfigOption(REDIS_OPTIONS.REPL_TIMEOUT, "" + replTimeout);
+        return this;
+    }
+
+    public RedisRunner replDisableTcpNodelay(boolean replDisableTcpNodelay) {
+        addConfigOption(REDIS_OPTIONS.REPL_DISABLE_TCP_NODELAY, convertBoolean(replDisableTcpNodelay));
+        return this;
+    }
+
+    public RedisRunner replBacklogSize(String replBacklogSize) {
+        addConfigOption(REDIS_OPTIONS.REPL_BACKLOG_SIZE, "" + replBacklogSize);
+        return this;
+    }
+
+    public RedisRunner replBacklogTtl(long replBacklogTtl) {
+        addConfigOption(REDIS_OPTIONS.REPL_BACKLOG_TTL, "" + replBacklogTtl);
+        return this;
+    }
+
+    public RedisRunner slavePriority(long slavePriority) {
+        addConfigOption(REDIS_OPTIONS.SLAVE_PRIORITY, "" + slavePriority);
+        return this;
+    }
+
+    public RedisRunner minSlaveToWrite(long minSlaveToWrite) {
+        addConfigOption(REDIS_OPTIONS.MIN_SLAVES_TO_WRITE, "" + minSlaveToWrite);
+        return this;
+    }
+
+    public RedisRunner minSlaveMaxLag(long minSlaveMaxLag) {
+        addConfigOption(REDIS_OPTIONS.MIN_SLAVES_MAX_LAG, "" + minSlaveMaxLag);
+        return this;
+    }
+
+    public RedisRunner requirepass(String requirepass) {
+        addConfigOption(REDIS_OPTIONS.REQUREPASS, requirepass);
+        return this;
+    }
+
+    public RedisRunner renameCommand(String renameCommand) {
+        addConfigOption(REDIS_OPTIONS.RENAME_COMMAND, renameCommand);
+        return this;
+    }
+
+    public RedisRunner maxclients(long maxclients) {
+        addConfigOption(REDIS_OPTIONS.MAXCLIENTS, "" + maxclients);
+        return this;
+    }
+
+    public RedisRunner maxmemory(String maxmemory) {
+        addConfigOption(REDIS_OPTIONS.MAXMEMORY, "" + maxmemory);
+        return this;
+    }
+
+    public RedisRunner maxmemoryPolicy(MAX_MEMORY_POLICY_OPTIONS maxmemoryPolicy) {
+        addConfigOption(REDIS_OPTIONS.MAXMEMORY, maxmemoryPolicy.toString());
+        return this;
+    }
+
+    public RedisRunner maxmemorySamples(long maxmemorySamples) {
+        addConfigOption(REDIS_OPTIONS.MAXMEMORY, "" + maxmemorySamples);
+        return this;
+    }
+
+    public RedisRunner appendonly(boolean appendonly) {
+        addConfigOption(REDIS_OPTIONS.APPENDONLY, convertBoolean(appendonly));
+        return this;
+    }
+
+    public RedisRunner appendfilename(String appendfilename) {
+        addConfigOption(REDIS_OPTIONS.APPENDFILENAME, appendfilename);
+        return this;
+    }
+
+    public RedisRunner appendfsync(APPEND_FSYNC_MODE_OPTIONS appendfsync) {
+        addConfigOption(REDIS_OPTIONS.APPENDFSYNC, appendfsync.toString());
+        return this;
+    }
+
+    public RedisRunner noAppendfsyncOnRewrite(boolean noAppendfsyncOnRewrite) {
+        addConfigOption(REDIS_OPTIONS.NO_APPENDFSYNC_ON_REWRITE, convertBoolean(noAppendfsyncOnRewrite));
+        return this;
+    }
+
+    public RedisRunner autoAofRewritePercentage(int autoAofRewritePercentage) {
+        addConfigOption(REDIS_OPTIONS.AUTO_AOF_REWRITE_PERCENTAGE, "" + autoAofRewritePercentage);
+        return this;
+    }
+
+    public RedisRunner autoAofRewriteMinSize(String autoAofRewriteMinSize) {
+        addConfigOption(REDIS_OPTIONS.AUTO_AOF_REWRITE_MIN_SIZE, autoAofRewriteMinSize);
+        return this;
+    }
+
+    public RedisRunner aofLoadTruncated(boolean aofLoadTruncated) {
+        addConfigOption(REDIS_OPTIONS.AOF_LOAD_TRUNCATED, convertBoolean(aofLoadTruncated));
+        return this;
+    }
+
+    public RedisRunner luaTimeLimit(long luaTimeLimit) {
+        addConfigOption(REDIS_OPTIONS.AOF_LOAD_TRUNCATED, "" + luaTimeLimit);
+        return this;
+    }
+
+    public RedisRunner clusterEnabled(boolean clusterEnabled) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_ENABLED, convertBoolean(clusterEnabled));
+        return this;
+    }
+
+    public RedisRunner clusterConfigFile(String clusterConfigFile) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_CONFIG_FILE, clusterConfigFile);
+        return this;
+    }
+
+    public RedisRunner clusterNodeTimeout(long clusterNodeTimeout) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_NODE_TIMEOUT, "" + clusterNodeTimeout);
+        return this;
+    }
+
+    public RedisRunner clusterSlaveValidityFactor(long clusterSlaveValidityFactor) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_SLAVE_VALIDITY_FACTOR, "" + clusterSlaveValidityFactor);
+        return this;
+    }
+
+    public RedisRunner clusterMigrationBarrier(long clusterMigrationBarrier) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_MIGRATION_BARRIER, "" + clusterMigrationBarrier);
+        return this;
+    }
+
+    public RedisRunner clusterRequireFullCoverage(boolean clusterRequireFullCoverage) {
+        addConfigOption(REDIS_OPTIONS.CLUSTER_REQUIRE_FULL_COVERAGE, convertBoolean(clusterRequireFullCoverage));
+        return this;
+    }
+
+    public RedisRunner slowlogLogSlowerThan(long slowlogLogSlowerThan) {
+        addConfigOption(REDIS_OPTIONS.SLOWLOG_LOG_SLOWER_THAN, "" + slowlogLogSlowerThan);
+        return this;
+    }
+
+    public RedisRunner slowlogMaxLen(long slowlogMaxLen) {
+        addConfigOption(REDIS_OPTIONS.SLOWLOG_MAX_LEN, "" + slowlogMaxLen);
+        return this;
+    }
+
+    public RedisRunner latencyMonitorThreshold(long latencyMonitorThreshold) {
+        addConfigOption(REDIS_OPTIONS.LATENCY_MONITOR_THRESHOLD, "" + latencyMonitorThreshold);
+        return this;
+    }
+
+    public RedisRunner notifyKeyspaceEvents(KEYSPACE_EVENTS_OPTIONS notifyKeyspaceEvents) {
+        String existing = this.options.getOrDefault(REDIS_OPTIONS.CLUSTER_CONFIG_FILE, "");
+        addConfigOption(REDIS_OPTIONS.CLUSTER_CONFIG_FILE,
+                existing.contains(notifyKeyspaceEvents.toString())
+                        ? existing
+                        : (existing + notifyKeyspaceEvents.toString()));
+        return this;
+    }
+
+    public RedisRunner hashMaxZiplistEntries(long hashMaxZiplistEntries) {
+        addConfigOption(REDIS_OPTIONS.HASH_MAX_ZIPLIST_ENTRIES, "" + hashMaxZiplistEntries);
+        return this;
+    }
+
+    public RedisRunner hashMaxZiplistValue(long hashMaxZiplistValue) {
+        addConfigOption(REDIS_OPTIONS.HASH_MAX_ZIPLIST_VALUE, "" + hashMaxZiplistValue);
+        return this;
+    }
+
+    public RedisRunner listMaxZiplistEntries(long listMaxZiplistEntries) {
+        addConfigOption(REDIS_OPTIONS.LIST_MAX_ZIPLIST_ENTRIES, "" + listMaxZiplistEntries);
+        return this;
+    }
+
+    public RedisRunner listMaxZiplistValue(long listMaxZiplistValue) {
+        addConfigOption(REDIS_OPTIONS.LIST_MAX_ZIPLIST_VALUE, "" + listMaxZiplistValue);
+        return this;
+    }
+
+    public RedisRunner setMaxIntsetEntries(long setMaxIntsetEntries) {
+        addConfigOption(REDIS_OPTIONS.SET_MAX_INTSET_ENTRIES, "" + setMaxIntsetEntries);
+        return this;
+    }
+
+    public RedisRunner zsetMaxZiplistEntries(long zsetMaxZiplistEntries) {
+        addConfigOption(REDIS_OPTIONS.ZSET_MAX_ZIPLIST_ENTRIES, "" + zsetMaxZiplistEntries);
+        return this;
+    }
+
+    public RedisRunner zsetMaxZiplistValue(long zsetMaxZiplistValue) {
+        addConfigOption(REDIS_OPTIONS.ZSET_MAX_ZIPLIST_VALUE, "" + zsetMaxZiplistValue);
+        return this;
+    }
+
+    public RedisRunner hllSparseMaxBytes(long hllSparseMaxBytes) {
+        addConfigOption(REDIS_OPTIONS.HLL_SPARSE_MAX_BYTES, "" + hllSparseMaxBytes);
+        return this;
     }
 
+    public RedisRunner activerehashing(boolean activerehashing) {
+        addConfigOption(REDIS_OPTIONS.ACTIVEREHASHING, convertBoolean(activerehashing));
+        return this;
+    }
+
+    public RedisRunner clientOutputBufferLimit$Normal(String hardLimit, String softLimit, long softSeconds) {
+        addConfigOption(REDIS_OPTIONS.CLIENT_OUTPUT_BUFFER_LIMIT$NORMAL, hardLimit, softLimit, "" + softSeconds);
+        return this;
+    }
+
+    public RedisRunner clientOutputBufferLimit$Slave(String hardLimit, String softLimit, long softSeconds) {
+        addConfigOption(REDIS_OPTIONS.CLIENT_OUTPUT_BUFFER_LIMIT$SLAVE, hardLimit, softLimit, "" + softSeconds);
+        return this;
+    }
+
+    public RedisRunner clientOutputBufferLimit$Pubsub(String hardLimit, String softLimit, long softSeconds) {
+        addConfigOption(REDIS_OPTIONS.CLIENT_OUTPUT_BUFFER_LIMIT$PUBSUB, hardLimit, softLimit, "" + softSeconds);
+        return this;
+    }
+
+    public RedisRunner hz(int hz) {
+        addConfigOption(REDIS_OPTIONS.HZ, "" + hz);
+        return this;
+    }
+
+    public RedisRunner aofRewriteIncrementalFsync(boolean aofRewriteIncrementalFsync) {
+        addConfigOption(REDIS_OPTIONS.AOF_REWRITE_INCREMENTAL_FSYNC, convertBoolean(aofRewriteIncrementalFsync));
+        return this;
+    }
+
+    public static final class RedisProcess {
+        private final Process redisProcess;
+        
+        private RedisProcess(Process redisProcess) {
+            this.redisProcess = redisProcess;
+        }
+        
+        public int stop() throws InterruptedException {
+            redisProcess.destroy();
+            int exitCode = redisProcess.waitFor();
+            return exitCode == 1 && isWindows() ? 0 : exitCode ;
+        }
+
+        public Process getRedisProcess() {
+            return redisProcess;
+        }
+        
+        private boolean isWindows() {
+            return System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH).contains("win");
+        }
+    }
+    
 }
diff --git a/src/test/java/org/redisson/RedissonMultiLockTest.java b/src/test/java/org/redisson/RedissonMultiLockTest.java
index 22e0cd1e7..9b5446a80 100644
--- a/src/test/java/org/redisson/RedissonMultiLockTest.java
+++ b/src/test/java/org/redisson/RedissonMultiLockTest.java
@@ -12,14 +12,15 @@ import org.redisson.core.RLock;
 import org.redisson.core.RedissonMultiLock;
 
 import io.netty.channel.nio.NioEventLoopGroup;
+import org.redisson.RedisRunner.RedisProcess;
 
 public class RedissonMultiLockTest {
 
     @Test
     public void test() throws IOException, InterruptedException {
-        Process redis1 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance1.conf");
-        Process redis2 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance2.conf");
-        Process redis3 = RedisRunner.runRedisWithConfigFile("/redis_multiLock_test_instance3.conf");
+        RedisProcess redis1 = redisTestMultilockInstance1();
+        RedisProcess redis2 = redisTestMultilockInstance2();
+        RedisProcess redis3 = redisTestMultilockInstance3();
 
         NioEventLoopGroup group = new NioEventLoopGroup();
         Config config1 = new Config();
@@ -65,14 +66,28 @@ public class RedissonMultiLockTest {
 
         lock.unlock();
 
-        redis1.destroy();
-        assertThat(redis1.waitFor()).isEqualTo(1);
+        assertThat(redis1.stop()).isEqualTo(0);
 
-        redis2.destroy();
-        assertThat(redis2.waitFor()).isEqualTo(1);
+        assertThat(redis2.stop()).isEqualTo(0);
 
-        redis3.destroy();
-        assertThat(redis3.waitFor()).isEqualTo(1);
+        assertThat(redis3.stop()).isEqualTo(0);
+    }
+    
+    private RedisProcess redisTestMultilockInstance1() throws IOException, InterruptedException {
+        return new RedisRunner()
+                .port(6320)
+                .run();
+    }
+    
+    private RedisProcess redisTestMultilockInstance2() throws IOException, InterruptedException {
+        return new RedisRunner()
+                .port(6321)
+                .run();
+    }
+    
+    private RedisProcess redisTestMultilockInstance3() throws IOException, InterruptedException {
+        return new RedisRunner()
+                .port(6322)
+                .run();
     }
-
 }
diff --git a/src/test/java/org/redisson/RedissonTest.java b/src/test/java/org/redisson/RedissonTest.java
index 73588a006..1cbeff418 100644
--- a/src/test/java/org/redisson/RedissonTest.java
+++ b/src/test/java/org/redisson/RedissonTest.java
@@ -41,6 +41,7 @@ import io.netty.channel.socket.nio.NioSocketChannel;
 import io.netty.util.concurrent.GenericFutureListener;
 
 import static com.jayway.awaitility.Awaitility.*;
+import org.redisson.RedisRunner.RedisProcess;
 
 public class RedissonTest {
 
@@ -61,7 +62,7 @@ public class RedissonTest {
     
     @Test(expected = RedisOutOfMemoryException.class)
     public void testMemoryScript() throws IOException, InterruptedException {
-        Process p = RedisRunner.runRedisWithConfigFile("/redis_oom_test.conf");
+        RedisProcess p = redisTestSmallMemory();
 
         Config config = new Config();
         config.useSingleServer().setAddress("127.0.0.1:6319").setTimeout(100000);
@@ -72,13 +73,13 @@ public class RedissonTest {
                 r.getMap("test").put("" + i, "" + i);
             }
         } finally {
-            p.destroy();
+            p.stop();
         }
     }
 
     @Test(expected = RedisOutOfMemoryException.class)
     public void testMemoryCommand() throws IOException, InterruptedException {
-        Process p = RedisRunner.runRedisWithConfigFile("/redis_oom_test.conf");
+        RedisProcess p = redisTestSmallMemory();
 
         Config config = new Config();
         config.useSingleServer().setAddress("127.0.0.1:6319").setTimeout(100000);
@@ -89,7 +90,7 @@ public class RedissonTest {
                 r.getMap("test").fastPut("" + i, "" + i);
             }
         } finally {
-            p.destroy();
+            p.stop();
         }
     }
 
@@ -97,7 +98,7 @@ public class RedissonTest {
     @Test
     public void testConnectionListener() throws IOException, InterruptedException, TimeoutException {
 
-        Process p = RedisRunner.runRedisWithConfigFile("/redis_connectionListener_test.conf");
+        RedisProcess p = redisTestConnection();
 
         final AtomicInteger connectCounter = new AtomicInteger();
         final AtomicInteger disconnectCounter = new AtomicInteger();
@@ -126,22 +127,20 @@ public class RedissonTest {
         assertThat(id).isNotZero();
 
         r.getBucket("1").get();
-        p.destroy();
-        Assert.assertEquals(1, p.waitFor());
+        Assert.assertEquals(0, p.stop());
 
         try {
             r.getBucket("1").get();
         } catch (Exception e) {
         }
 
-        p = RedisRunner.runRedisWithConfigFile("/redis_connectionListener_test.conf");
+        p = redisTestConnection();
 
         r.getBucket("1").get();
 
         r.shutdown();
 
-        p.destroy();
-        Assert.assertEquals(1, p.waitFor());
+        Assert.assertEquals(0, p.stop());
 
         await().atMost(1, TimeUnit.SECONDS).until(() -> assertThat(connectCounter.get()).isEqualTo(2));
         await().until(() -> assertThat(disconnectCounter.get()).isEqualTo(1));
@@ -282,5 +281,17 @@ public class RedissonTest {
         r.shutdown();
     }
 
+    private RedisProcess redisTestSmallMemory() throws IOException, InterruptedException {
+        return new RedisRunner()
+                .maxmemory("1mb")
+                .port(6319)
+                .run();
+    }
 
+    private RedisProcess redisTestConnection() throws IOException, InterruptedException {
+        return new RedisRunner()
+                .port(6319)
+                .run();
+    }
+    
 }