Skip to content

Commit

Permalink
implement isRunning and fix a minor thread leak on RedisServer::stop (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
inponomarev authored Jul 6, 2024
1 parent 4246c43 commit cd0602c
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 8 deletions.
24 changes: 16 additions & 8 deletions src/main/java/com/github/fppt/jedismock/RedisServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
*/
public class RedisServer {

private static final String NOT_RUNNING = "JedisMock is not running";

private final int bindPort;
private final InetAddress bindAddress;
private final Map<Integer, RedisBase> redisBases;
private final ExecutorService threadPool;
private RedisService service;
private ServiceOptions options = ServiceOptions.defaultOptions();
private Future<Void> serviceFinalization;
private volatile ExecutorService threadPool;
private volatile RedisService service;
private volatile ServiceOptions options = ServiceOptions.defaultOptions();
private volatile Future<Void> serviceFinalization;

public RedisServer() {
this(0);
Expand All @@ -41,7 +43,6 @@ public RedisServer(int port, InetAddress address) {
this.bindPort = port;
this.bindAddress = address;
this.redisBases = new HashMap<>();
this.threadPool = Executors.newSingleThreadExecutor();
CommandFactory.initialize();
}

Expand All @@ -68,12 +69,13 @@ public RedisServer start() throws IOException {
throw new IllegalStateException();
}
this.service = new RedisService(bindPort, bindAddress, redisBases, options);
threadPool = Executors.newSingleThreadExecutor();
serviceFinalization = threadPool.submit(service);
return this;
}

public void stop() throws IOException {
Objects.requireNonNull(service);
Objects.requireNonNull(service, NOT_RUNNING);
service.stop();
service = null;
try {
Expand All @@ -83,16 +85,22 @@ public void stop() throws IOException {
} catch (InterruptedException e) {
System.err.println("Jedis-mock interrupted while stopping");
Thread.currentThread().interrupt();
} finally {
threadPool.shutdownNow();
}
}

public boolean isRunning() {
return service != null;
}

public String getHost() {
Objects.requireNonNull(service);
Objects.requireNonNull(service, NOT_RUNNING);
return service.getServer().getInetAddress().getHostAddress();
}

public int getBindPort() {
Objects.requireNonNull(service);
Objects.requireNonNull(service, NOT_RUNNING);
return service.getServer().getLocalPort();
}
}
73 changes: 73 additions & 0 deletions src/test/java/com/github/fppt/jedismock/TestStartStop.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.github.fppt.jedismock;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class TestStartStop {
@Test
void testMultipleServerReuse() throws IOException {
Set<String> oldThreads = threadNames();
RedisServer server = RedisServer.newRedisServer();
for (int i = 0; i < 2000; i++) {
startCheckStop(server);
}
Set<String> newThreads = threadNames();
newThreads.removeAll(oldThreads);
Assertions.assertThat(newThreads).hasSizeLessThan(10);
}

@Test
void testMultipleServerCreation() throws IOException {
Set<String> oldThreads = threadNames();
for (int i = 0; i < 2000; i++) {
RedisServer server = RedisServer.newRedisServer();
startCheckStop(server);
}
Set<String> newThreads = threadNames();
newThreads.removeAll(oldThreads);
Assertions.assertThat(newThreads).hasSizeLessThan(10);
}

@Test
void testStartAlreadyStarted() throws IOException {
RedisServer server = RedisServer.newRedisServer();
server.start();
try {
Assertions.assertThatThrownBy(server::start).isInstanceOf(IllegalStateException.class);
} finally {
server.stop();
}
}

@Test
void testStopNotStarted() {
RedisServer server = RedisServer.newRedisServer();
Assertions.assertThatThrownBy(server::stop).hasMessageContaining("is not running");
}

private static Set<String> threadNames() {
return Thread.getAllStackTraces()
.keySet()
.stream()
.map(Thread::getName)
.collect(Collectors.toCollection(HashSet::new));
}

private static void startCheckStop(RedisServer server) throws IOException {
Assertions.assertThat(server.isRunning()).isFalse();
server.start();
Assertions.assertThat(server.isRunning()).isTrue();
try (Jedis jedis = new Jedis(server.getHost(), server.getBindPort())) {
Assertions.assertThat(jedis.ping()).isEqualTo("PONG");
}
server.stop();
Assertions.assertThat(server.isRunning()).isFalse();
}

}

0 comments on commit cd0602c

Please sign in to comment.