Skip to content

Commit 32310e4

Browse files
committed
added modules and cluster keyspace notifications
1 parent 1cda500 commit 32310e4

18 files changed

+494
-262
lines changed

build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ dependencies {
3232
api group: 'org.testcontainers', name: 'testcontainers', version: testcontainers_version
3333
api group: 'org.testcontainers', name: 'junit-jupiter', version: testcontainers_version
3434
testImplementation 'com.redislabs:mesclun:1.2.2'
35-
testImplementation 'org.slf4j:slf4j-jdk14:1.7.30'
35+
testImplementation 'org.slf4j:slf4j-simple:1.7.30'
36+
testImplementation group: 'org.projectlombok', name: 'lombok', version: lombok_version
37+
testAnnotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok_version
3638
}
3739

3840
test {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.redislabs.testcontainers;
2+
3+
import org.testcontainers.containers.GenericContainer;
4+
import org.testcontainers.containers.wait.strategy.Wait;
5+
import org.testcontainers.shaded.org.apache.commons.lang.ClassUtils;
6+
import org.testcontainers.utility.DockerImageName;
7+
8+
public abstract class AbstractRedisContainer<C extends AbstractRedisContainer<C>> extends GenericContainer<C> implements RedisContainer {
9+
10+
public static final int REDIS_PORT = 6379;
11+
12+
protected AbstractRedisContainer(final DockerImageName dockerImageName) {
13+
this(dockerImageName, REDIS_PORT);
14+
}
15+
16+
protected AbstractRedisContainer(final DockerImageName dockerImageName, int port) {
17+
super(dockerImageName);
18+
withExposedPorts(port);
19+
waitingFor(Wait.forLogMessage(".*Ready to accept connections.*\\n", 1));
20+
}
21+
22+
/**
23+
* Get Redis URI.
24+
*
25+
* @return Redis URI.
26+
*/
27+
@Override
28+
public String getRedisURI() {
29+
return RedisContainerUtils.redisURI(this);
30+
}
31+
32+
@Override
33+
public String toString() {
34+
return ClassUtils.getShortClassName(getClass());
35+
}
36+
37+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.redislabs.testcontainers;
2+
3+
import org.testcontainers.containers.FixedHostPortGenericContainer;
4+
import org.testcontainers.containers.wait.strategy.Wait;
5+
import org.testcontainers.utility.MountableFile;
6+
7+
public class RedisClusterContainer extends FixedHostPortGenericContainer<RedisClusterContainer> implements RedisContainer {
8+
9+
private static final String ENV_MASTERS = "MASTERS";
10+
private static final String ENV_SLAVES_PER_MASTER = "SLAVES_PER_MASTER";
11+
private static final String ENV_INITIAL_PORT = "INITIAL_PORT";
12+
private static final String ENV_IP = "IP";
13+
14+
private static final String DEFAULT_IMAGE_NAME = "grokzen/redis-cluster:6.2.1";
15+
private static final String KEYSPACE_NOTIFICATIONS_IMAGE_NAME = "jruaux/redis-cluster:6.2.1";
16+
private static final int DEFAULT_INITIAL_PORT = 7000;
17+
private static final int DEFAULT_MASTERS = 3;
18+
private static final int DEFAULT_SLAVES_PER_MASTER = 0;
19+
private static final String DEFAULT_IP = "0.0.0.0";
20+
21+
private int initialPort = DEFAULT_INITIAL_PORT;
22+
private int masters = DEFAULT_MASTERS;
23+
private int slavesPerMaster = DEFAULT_SLAVES_PER_MASTER;
24+
25+
public RedisClusterContainer() {
26+
this(DEFAULT_IMAGE_NAME);
27+
}
28+
29+
protected RedisClusterContainer(final String dockerImageName) {
30+
super(dockerImageName);
31+
withIP(DEFAULT_IP);
32+
update();
33+
waitingFor(Wait.forLogMessage(".*Cluster state changed: ok*\\n", 1));
34+
}
35+
36+
public RedisClusterContainer withKeyspaceNotifications() {
37+
setDockerImageName(KEYSPACE_NOTIFICATIONS_IMAGE_NAME);
38+
return this;
39+
}
40+
41+
public RedisClusterContainer withIP(String ip) {
42+
withEnv(ENV_IP, ip);
43+
return this;
44+
}
45+
46+
private RedisClusterContainer update() {
47+
withEnv(ENV_INITIAL_PORT, String.valueOf(initialPort));
48+
withEnv(ENV_MASTERS, String.valueOf(masters));
49+
withEnv(ENV_SLAVES_PER_MASTER, String.valueOf(slavesPerMaster));
50+
for (int port : ports()) {
51+
withFixedExposedPort(port, port);
52+
}
53+
return this;
54+
}
55+
56+
private int[] ports() {
57+
int totalNodes = masters * (slavesPerMaster + 1);
58+
int[] ports = new int[totalNodes];
59+
for (int index = 0; index < totalNodes; index++) {
60+
ports[index] = initialPort + index;
61+
}
62+
return ports;
63+
}
64+
65+
public String[] getRedisURIs() {
66+
int[] ports = ports();
67+
String[] redisURIs = new String[ports.length];
68+
for (int index = 0; index < ports.length; index++) {
69+
redisURIs[index] = RedisContainerUtils.redisURI(getHost(), ports[index]);
70+
}
71+
return redisURIs;
72+
}
73+
74+
public String getRedisURI() {
75+
return getRedisURIs()[0];
76+
}
77+
78+
public RedisClusterContainer withMasters(int count) {
79+
if (count <= 0) {
80+
throw new IllegalArgumentException("Count must be greater than zero");
81+
}
82+
this.masters = masters;
83+
return update();
84+
}
85+
86+
public RedisClusterContainer withSlavesPerMaster(int count) {
87+
if (count < 0) {
88+
throw new IllegalArgumentException("Count must be zero or greater");
89+
}
90+
this.slavesPerMaster = count;
91+
return update();
92+
}
93+
94+
public RedisClusterContainer withInitialPort(int port) {
95+
this.initialPort = port;
96+
return update();
97+
}
98+
99+
}
Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,7 @@
11
package com.redislabs.testcontainers;
22

3-
import lombok.Getter;
4-
import org.testcontainers.containers.GenericContainer;
5-
import org.testcontainers.containers.wait.strategy.Wait;
6-
import org.testcontainers.utility.DockerImageName;
7-
import org.testcontainers.utility.MountableFile;
3+
public interface RedisContainer {
84

9-
/**
10-
* This container wraps Redis and optionally Redis Cluster
11-
* Some code borrowed from https://github.com/jaredpetersen/kafka-connect-redis
12-
*/
13-
public class RedisContainer extends GenericContainer<RedisContainer> {
14-
15-
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("redis");
16-
private static final String DEFAULT_TAG = "6";
17-
18-
public static final int REDIS_PORT = 6379;
19-
20-
@Getter
21-
private boolean cluster;
22-
23-
public RedisContainer() {
24-
this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG));
25-
}
26-
27-
protected RedisContainer(final DockerImageName dockerImageName) {
28-
super(dockerImageName);
29-
dockerImageName.assertCompatibleWith(defaultImageName());
30-
withExposedPorts(REDIS_PORT);
31-
waitingFor(Wait.forLogMessage(".*Ready to accept connections.*\\n", 1));
32-
}
33-
34-
protected DockerImageName defaultImageName() {
35-
return DEFAULT_IMAGE_NAME;
36-
}
37-
38-
@SuppressWarnings("unchecked")
39-
public <C extends RedisContainer> C withKeyspaceNotifications() {
40-
withCopyFileToContainer(MountableFile.forClasspathResource("redis-keyspace-notifications.conf"), "/data/redis.conf");
41-
withCommand("redis-server", "/data/redis.conf");
42-
return (C) this;
43-
}
44-
45-
public <C extends RedisContainer> C withClusterKeyspaceNotifications() {
46-
return withClusterMode("redis-cluster-keyspace-notifications.conf");
47-
}
48-
49-
/**
50-
* Enables Redis cluster mode
51-
*
52-
* @param <C> this RedisContainer instance
53-
* @return a Redis Cluster container
54-
*/
55-
public <C extends RedisContainer> C withClusterMode() {
56-
return withClusterMode("redis-cluster.conf");
57-
}
58-
59-
@SuppressWarnings("unchecked")
60-
private <C extends RedisContainer> C withClusterMode(String conf) {
61-
withCopyFileToContainer(MountableFile.forClasspathResource(conf), "/data/redis-cluster.conf");
62-
withCopyFileToContainer(MountableFile.forClasspathResource("nodes-cluster.conf"), "/data/nodes.conf");
63-
withCommand("redis-server", "/data/redis-cluster.conf");
64-
waitingFor(Wait.forLogMessage(".*Cluster state changed: ok*\\n", 1));
65-
cluster = true;
66-
return (C) this;
67-
}
68-
69-
/**
70-
* Get Redis URI.
71-
*
72-
* @return Redis URI.
73-
*/
74-
public String getRedisUri() {
75-
return "redis://" + this.getHost() + ":" + this.getFirstMappedPort();
76-
}
77-
78-
@Override
79-
public String toString() {
80-
if (cluster) {
81-
return "cluster " + getRedisUri();
82-
}
83-
return getRedisUri();
84-
}
5+
String getRedisURI();
856

867
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.redislabs.testcontainers;
2+
3+
import org.testcontainers.containers.GenericContainer;
4+
5+
public class RedisContainerUtils {
6+
7+
public static String redisURI(String host, int port) {
8+
return "redis://" + host + ":" + port;
9+
}
10+
11+
public static String redisURI(GenericContainer<?> container) {
12+
return redisURI(container.getHost(), container.getFirstMappedPort());
13+
}
14+
15+
}

src/main/java/com/redislabs/testcontainers/RedisModulesContainer.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,17 @@
22

33
import org.testcontainers.utility.DockerImageName;
44

5-
public class RedisModulesContainer extends RedisContainer {
5+
public class RedisModulesContainer extends AbstractRedisContainer<RedisModulesContainer> {
66

77
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("redislabs/redismod");
88
private static final String DEFAULT_TAG = "latest";
99

1010
public RedisModulesContainer() {
11-
super(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG));
11+
this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG));
1212
}
1313

14-
public RedisModulesContainer(final DockerImageName dockerImageName) {
14+
protected RedisModulesContainer(final DockerImageName dockerImageName) {
1515
super(dockerImageName);
1616
}
1717

18-
@Override
19-
protected DockerImageName defaultImageName() {
20-
return DEFAULT_IMAGE_NAME;
21-
}
22-
23-
@Override
24-
public <C extends RedisContainer> C withKeyspaceNotifications() {
25-
throw new UnsupportedOperationException("RedisModulesContainer does not support keyspace notifications");
26-
}
27-
28-
@Override
29-
public <C extends RedisContainer> C withClusterKeyspaceNotifications() {
30-
throw new UnsupportedOperationException("RedisModulesContainer does not support keyspace notifications");
31-
}
32-
33-
@Override
34-
public <C extends RedisContainer> C withClusterMode() {
35-
throw new UnsupportedOperationException("RedisModulesContainer does not support cluster mode");
36-
}
3718
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.redislabs.testcontainers;
2+
3+
import org.testcontainers.utility.DockerImageName;
4+
import org.testcontainers.utility.MountableFile;
5+
6+
public class RedisStandaloneContainer extends AbstractRedisContainer<RedisStandaloneContainer> {
7+
8+
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("redis");
9+
private static final String DEFAULT_TAG = "latest";
10+
11+
public RedisStandaloneContainer() {
12+
this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG));
13+
}
14+
15+
protected RedisStandaloneContainer(final DockerImageName dockerImageName) {
16+
super(dockerImageName);
17+
}
18+
19+
@SuppressWarnings("unchecked")
20+
public <C extends RedisStandaloneContainer> C withKeyspaceNotifications() {
21+
withCopyFileToContainer(MountableFile.forClasspathResource("redis-keyspace-notifications.conf"), "/data/redis.conf");
22+
withCommand("redis-server", "/data/redis.conf");
23+
return (C) this;
24+
}
25+
26+
}

src/main/resources/nodes-cluster.conf

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/main/resources/redis-cluster-keyspace-notifications.conf

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/main/resources/redis-cluster.conf

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)