@ -6,12 +6,21 @@ import java.io.IOException;
import java.io.InputStreamReader ;
import java.net.Inet4Address ;
import java.net.URL ;
import java.nio.file.Paths ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.HashSet ;
import java.util.LinkedHashMap ;
import java.util.List ;
import java.util.Locale ;
import java.util.Optional ;
import java.util.UUID ;
import java.util.concurrent.TimeUnit ;
import java.util.stream.Collectors ;
import org.redisson.client.RedisClient ;
import org.redisson.client.protocol.RedisCommands ;
import org.redisson.client.protocol.RedisStrictCommand ;
import org.redisson.client.protocol.convertor.VoidReplayConvertor ;
public class RedisRunner {
@ -161,11 +170,16 @@ public class RedisRunner {
}
private static final String redisBinary ;
private final LinkedHashMap < REDIS_OPTIONS , String > options = new LinkedHashMap < > ( ) ;
private static RedisRunner . RedisProcess defaultRedisInstance ;
private static int defaultRedisInstanceExitCode ;
private String defaultDir = Paths . get ( "" ) . toString ( ) ;
private boolean nosave = false ;
private boolean randomDir = false ;
private ArrayList < String > bindAddr = new ArrayList < > ( ) ;
private int port = 6379 ;
static {
redisBinary = Optional . ofNullable ( System . getProperty ( "redisBinary" ) )
. orElse ( "C:\\Devel\\projects\\redis\\Redis-x64-3.0.500\\redis-server.exe" ) ;
@ -192,17 +206,17 @@ public class RedisRunner {
* /
public static RedisProcess runRedisWithConfigFile ( String configPath ) throws IOException , InterruptedException {
URL resource = RedisRunner . class . getResource ( configPath ) ;
return runWithOptions ( redisBinary , resource . getFile ( ) ) ;
return runWithOptions ( new RedisRunner ( ) , redisBinary , resource . getFile ( ) ) ;
}
private static RedisProcess runWithOptions ( String. . . options ) throws IOException , InterruptedException {
private static RedisProcess runWithOptions ( RedisRunner runner , String. . . options ) throws IOException , InterruptedException {
List < String > launchOptions = Arrays . stream ( options )
. map ( x - > Arrays . asList ( x . split ( " " ) ) ) . flatMap ( x - > x . stream ( ) )
. collect ( Collectors . toList ( ) ) ;
System . out . println ( "REDIS LAUNCH OPTIONS: " + Arrays . toString ( launchOptions . toArray ( ) ) ) ;
ProcessBuilder master = new ProcessBuilder ( launchOptions )
. redirectErrorStream ( true )
. directory ( new File ( redisBinary) . getParentFile ( ) ) ;
. directory ( new File ( System. getProperty ( "java.io.tmpdir" ) ) ) ;
Process p = master . start ( ) ;
new Thread ( ( ) - > {
BufferedReader reader = new BufferedReader ( new InputStreamReader ( p . getInputStream ( ) ) ) ;
@ -216,11 +230,14 @@ public class RedisRunner {
}
} ) . start ( ) ;
Thread . sleep ( 3000 ) ;
return new RedisProcess ( p );
return new RedisProcess ( p , runner );
}
public RedisProcess run ( ) throws IOException , InterruptedException {
return runWithOptions ( options . values ( ) . toArray ( new String [ 0 ] ) ) ;
if ( ! options . containsKey ( REDIS_OPTIONS . DIR ) ) {
options . put ( REDIS_OPTIONS . DIR , defaultDir ) ;
}
return runWithOptions ( this , options . values ( ) . toArray ( new String [ 0 ] ) ) ;
}
private void addConfigOption ( REDIS_OPTIONS option , Object . . . args ) {
@ -253,9 +270,14 @@ public class RedisRunner {
}
public RedisRunner port ( int port ) {
this . port = port ;
addConfigOption ( REDIS_OPTIONS . PORT , port ) ;
return this ;
}
public int getPort ( ) {
return this . port ;
}
public RedisRunner tcpBacklog ( long tcpBacklog ) {
addConfigOption ( REDIS_OPTIONS . TCP_BACKLOG , tcpBacklog ) ;
@ -263,10 +285,15 @@ public class RedisRunner {
}
public RedisRunner bind ( String bind ) {
this . bindAddr . add ( bind ) ;
addConfigOption ( REDIS_OPTIONS . BIND , bind ) ;
return this ;
}
public ArrayList < String > getBindAddr ( ) {
return this . bindAddr ;
}
public RedisRunner unixsocket ( String unixsocket ) {
addConfigOption ( REDIS_OPTIONS . UNIXSOCKET , unixsocket ) ;
return this ;
@ -318,7 +345,21 @@ public class RedisRunner {
}
public RedisRunner save ( long seconds , long changes ) {
addConfigOption ( REDIS_OPTIONS . SAVE , seconds , changes ) ;
if ( ! nosave ) {
addConfigOption ( REDIS_OPTIONS . SAVE , seconds , changes ) ;
}
return this ;
}
/ * *
* Phantom option
*
* @return RedisRunner
* /
public RedisRunner nosave ( ) {
this . nosave = true ;
options . remove ( REDIS_OPTIONS . SAVE ) ;
addConfigOption ( REDIS_OPTIONS . SAVE , "" ) ;
return this ;
}
@ -343,7 +384,21 @@ public class RedisRunner {
}
public RedisRunner dir ( String dir ) {
addConfigOption ( REDIS_OPTIONS . DIR , dir ) ;
if ( ! randomDir ) {
addConfigOption ( REDIS_OPTIONS . DIR , dir ) ;
}
return this ;
}
/ * *
* Phantom option
* @return RedisRunner
* /
public RedisRunner randomDir ( ) {
this . randomDir = true ;
options . remove ( REDIS_OPTIONS . DIR ) ;
makeRandomDefaultDir ( ) ;
addConfigOption ( REDIS_OPTIONS . DIR , defaultDir ) ;
return this ;
}
@ -611,17 +666,62 @@ public class RedisRunner {
return this ;
}
public boolean isRandomDir ( ) {
return this . randomDir ;
}
public boolean isNosave ( ) {
return this . nosave ;
}
public String defaultDir ( ) {
return this . defaultDir ;
}
public boolean deleteDBfileDir ( ) {
File f = new File ( defaultDir ) ;
if ( f . exists ( ) ) {
System . out . println ( "RedisRunner: Deleting directory " + defaultDir ) ;
return f . delete ( ) ;
}
return false ;
}
private void makeRandomDefaultDir ( ) {
File f = new File ( System . getProperty ( "java.io.tmpdir" ) + "/" + UUID . randomUUID ( ) ) ;
if ( f . exists ( ) ) {
makeRandomDefaultDir ( ) ;
} else {
System . out . println ( "RedisRunner: Making directory " + f . getAbsolutePath ( ) ) ;
f . mkdirs ( ) ;
this . defaultDir = f . getAbsolutePath ( ) ;
}
}
public static final class RedisProcess {
private final Process redisProcess ;
private final RedisRunner runner ;
private RedisProcess ( Process redisProcess ) {
private RedisProcess ( Process redisProcess , RedisRunner runner ) {
this . redisProcess = redisProcess ;
this . runner = runner ;
}
public int stop ( ) throws InterruptedException {
if ( runner . isNosave ( ) ) {
ArrayList < String > b = runner . getBindAddr ( ) ;
RedisClient c = new RedisClient ( b . size ( ) > 0 ? b . get ( 0 ) : "localhost" , runner . getPort ( ) ) ;
c . connect ( )
. async ( new RedisStrictCommand < Void > ( "SHUTDOWN" , "NOSAVE" , new VoidReplayConvertor ( ) ) )
. await ( 3 , TimeUnit . SECONDS ) ;
c . shutdown ( ) ;
}
redisProcess . destroy ( ) ;
int exitCode = redisProcess . waitFor ( ) ;
int exitCode = redisProcess . isAlive ( ) ? redisProcess . waitFor ( ) : redisProcess . exitValue ( ) ;
if ( runner . isRandomDir ( ) ) {
runner . deleteDBfileDir ( ) ;
}
return exitCode = = 1 & & isWindows ( ) ? 0 : exitCode ;
}
@ -637,7 +737,7 @@ public class RedisRunner {
public static RedisRunner . RedisProcess startDefaultRedisTestInstance ( ) throws IOException , InterruptedException {
if ( defaultRedisInstance = = null ) {
System . out . println ( "REDIS PROCESS: Starting up default instance..." ) ;
defaultRedisInstance = new RedisRunner ( ) . run( ) ;
defaultRedisInstance = new RedisRunner ( ) . nosave( ) . randomDir ( ) . run( ) ;
Runtime . getRuntime ( ) . addShutdownHook ( new Thread ( ( ) - > {
try {
shutDownDefaultRedisTestInstance ( ) ;
@ -652,11 +752,14 @@ public class RedisRunner {
if ( defaultRedisInstance ! = null ) {
System . out . println ( "REDIS PROCESS: Shutting down default instance..." ) ;
try {
return defaultRedisInstance . stop ( ) ;
defaultRedisInstanceExitCode = defaultRedisInstance . stop ( ) ;
} finally {
defaultRedisInstance = null ;
}
} else {
System . out . println ( "REDIS PROCESS: Default instance is already down with an exit code " + defaultRedisInstanceExitCode ) ;
}
throw new IllegalStateException ( "REDIS PROCESS: Default redis instance is not running." ) ;
return defaultRedisInstanceExitCode ;
}
}