Skip to content

Commit e7771d2

Browse files
committed
Add migration tests for JedisCluster constructors used by SDR, Conductor and other OSS projects
1 parent b021db3 commit e7771d2

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
package redis.clients.jedis.builders;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertNotNull;
5+
6+
import java.util.HashSet;
7+
import java.util.Set;
8+
9+
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
10+
import org.junit.jupiter.api.AfterEach;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Tag;
13+
import org.junit.jupiter.api.Test;
14+
15+
import redis.clients.jedis.Connection;
16+
import redis.clients.jedis.ConnectionPoolConfig;
17+
import redis.clients.jedis.DefaultJedisClientConfig;
18+
import redis.clients.jedis.HostAndPort;
19+
import redis.clients.jedis.HostAndPorts;
20+
import redis.clients.jedis.JedisClientConfig;
21+
import redis.clients.jedis.JedisCluster;
22+
import redis.clients.jedis.RedisClusterClient;
23+
24+
/**
25+
* Integration test that verifies migration compatibility from the legacy JedisCluster constructor
26+
* to the new RedisClusterClient.Builder pattern.
27+
* <p>
28+
* This test demonstrates that the following legacy JedisCluster constructor:
29+
*
30+
* <pre>
31+
* public JedisCluster(Set&lt;HostAndPort&gt; clusterNodes, JedisClientConfig clientConfig,
32+
* int maxAttempts, GenericObjectPoolConfig&lt;Connection&gt; poolConfig)
33+
* </pre>
34+
*
35+
* can be replaced with the RedisClusterClient.Builder pattern while maintaining the same
36+
* functionality.
37+
*/
38+
@Tag("integration")
39+
public class RedisClusterClientMigrationIntegrationTest {
40+
41+
private static final Set<HostAndPort> CLUSTER_NODES = new HashSet<>(
42+
HostAndPorts.getStableClusterServers());
43+
private static final String PASSWORD = "cluster";
44+
private static final int MAX_ATTEMPTS = 3;
45+
46+
private JedisCluster legacyCluster;
47+
private RedisClusterClient newCluster;
48+
49+
@BeforeEach
50+
public void setUp() {
51+
// Clean up any existing data before each test
52+
cleanClusterData();
53+
}
54+
55+
@AfterEach
56+
public void tearDown() {
57+
// Close connections
58+
if (legacyCluster != null) {
59+
legacyCluster.close();
60+
legacyCluster = null;
61+
}
62+
if (newCluster != null) {
63+
newCluster.close();
64+
newCluster = null;
65+
}
66+
67+
// Clean up data after tests
68+
cleanClusterData();
69+
}
70+
71+
/**
72+
* Test that verifies both approaches can handle cluster operations correctly. Tests constructor:
73+
* JedisCluster(Set&lt;HostAndPort&gt;, JedisClientConfig, int,
74+
* GenericObjectPoolConfig&lt;Connection&gt;)
75+
*/
76+
@Test
77+
public void testSpringDataRedisConstructor() {
78+
// Prepare common configuration
79+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().password(PASSWORD)
80+
.socketTimeoutMillis(2000).connectionTimeoutMillis(2000).build();
81+
82+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
83+
84+
// Create both cluster clients
85+
legacyCluster = new JedisCluster(CLUSTER_NODES, clientConfig, MAX_ATTEMPTS, poolConfig);
86+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
87+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
88+
89+
verifyBothClients(legacyCluster, newCluster);
90+
}
91+
92+
/**
93+
* Test migration from constructor with username, password, clientName, and SSL. Tests
94+
* constructor: JedisCluster(Set&lt;HostAndPort&gt;, int, int, int, String, String, String,
95+
* GenericObjectPoolConfig&lt;Connection&gt;, boolean)
96+
*/
97+
@Test
98+
public void testConstructorWithUsernamePasswordClientNameAndSsl() {
99+
int connectionTimeout = 2000;
100+
int socketTimeout = 2000;
101+
String username = "default";
102+
String clientName = "test-client";
103+
boolean ssl = false; // SSL requires special cluster setup
104+
105+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
106+
107+
// Legacy constructor with username
108+
legacyCluster = new JedisCluster(CLUSTER_NODES, connectionTimeout, socketTimeout, MAX_ATTEMPTS,
109+
username, PASSWORD, clientName, poolConfig, ssl);
110+
111+
// New Builder pattern
112+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder()
113+
.connectionTimeoutMillis(connectionTimeout).socketTimeoutMillis(socketTimeout)
114+
.user(username).password(PASSWORD).clientName(clientName).ssl(ssl).build();
115+
116+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
117+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
118+
119+
verifyBothClients(legacyCluster, newCluster);
120+
}
121+
122+
/**
123+
* Test migration from constructor with password, clientName, and SSL (no username). Tests
124+
* constructor: JedisCluster(Set&lt;HostAndPort&gt;, int, int, int, String, String,
125+
* GenericObjectPoolConfig&lt;Connection&gt;, boolean)
126+
*/
127+
@Test
128+
public void testConstructorWithPasswordClientNameAndSsl() {
129+
int connectionTimeout = 2000;
130+
int socketTimeout = 2000;
131+
String clientName = "test-client";
132+
boolean ssl = false; // SSL requires special cluster setup
133+
134+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
135+
136+
// Legacy constructor without username
137+
legacyCluster = new JedisCluster(CLUSTER_NODES, connectionTimeout, socketTimeout, MAX_ATTEMPTS,
138+
PASSWORD, clientName, poolConfig, ssl);
139+
140+
// New Builder pattern
141+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder()
142+
.connectionTimeoutMillis(connectionTimeout).socketTimeoutMillis(socketTimeout)
143+
.password(PASSWORD).clientName(clientName).ssl(ssl).build();
144+
145+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
146+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
147+
148+
verifyBothClients(legacyCluster, newCluster);
149+
}
150+
151+
/**
152+
* Test migration from simple constructor with just nodes and poolConfig. Tests constructor:
153+
* JedisCluster(Set&lt;HostAndPort&gt;, GenericObjectPoolConfig&lt;Connection&gt;)
154+
*/
155+
@Test
156+
public void testConstructorWithNodesAndPoolConfig() {
157+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
158+
poolConfig.setMaxTotal(8);
159+
poolConfig.setMaxIdle(8);
160+
161+
// Legacy constructor
162+
legacyCluster = new JedisCluster(CLUSTER_NODES, poolConfig);
163+
164+
// New Builder pattern - need to add password via clientConfig
165+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().password(PASSWORD).build();
166+
167+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
168+
.poolConfig(poolConfig).build();
169+
170+
verifyBothClients(legacyCluster, newCluster);
171+
}
172+
173+
/**
174+
* Test migration from constructor with connection timeout, socket timeout, maxAttempts, password,
175+
* and poolConfig. Tests constructor: JedisCluster(Set&lt;HostAndPort&gt;, int, int, int, String,
176+
* GenericObjectPoolConfig&lt;Connection&gt;)
177+
*/
178+
@Test
179+
public void testConstructorWithTimeoutsPasswordAndPoolConfig() {
180+
int connectionTimeout = 2000;
181+
int socketTimeout = 2000;
182+
183+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
184+
185+
// Legacy constructor
186+
legacyCluster = new JedisCluster(CLUSTER_NODES, connectionTimeout, socketTimeout, MAX_ATTEMPTS,
187+
PASSWORD, poolConfig);
188+
189+
// New Builder pattern
190+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder()
191+
.connectionTimeoutMillis(connectionTimeout).socketTimeoutMillis(socketTimeout)
192+
.password(PASSWORD).build();
193+
194+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
195+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
196+
197+
verifyBothClients(legacyCluster, newCluster);
198+
}
199+
200+
/**
201+
* Test migration from constructor with connection timeout, socket timeout, maxAttempts, and
202+
* poolConfig (no password). Tests constructor: JedisCluster(Set&lt;HostAndPort&gt;, int, int,
203+
* int, GenericObjectPoolConfig&lt;Connection&gt;)
204+
*/
205+
@Test
206+
public void testConstructorWithTimeoutsAndPoolConfigNoPassword() {
207+
int connectionTimeout = 2000;
208+
int socketTimeout = 2000;
209+
210+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
211+
212+
// Legacy constructor without password
213+
legacyCluster = new JedisCluster(CLUSTER_NODES, connectionTimeout, socketTimeout, MAX_ATTEMPTS,
214+
poolConfig);
215+
216+
// New Builder pattern - need to add password for our test cluster
217+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder()
218+
.connectionTimeoutMillis(connectionTimeout).socketTimeoutMillis(socketTimeout)
219+
.password(PASSWORD).build();
220+
221+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
222+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
223+
224+
verifyBothClients(legacyCluster, newCluster);
225+
}
226+
227+
/**
228+
* Test migration from constructor with timeout, maxAttempts, and poolConfig. Tests constructor:
229+
* JedisCluster(Set&lt;HostAndPort&gt;, int, int, GenericObjectPoolConfig&lt;Connection&gt;)
230+
*/
231+
@Test
232+
public void testConstructorWithTimeoutMaxAttemptsAndPoolConfig() {
233+
int timeout = 2000;
234+
235+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
236+
237+
// Legacy constructor - uses same timeout for connection and socket
238+
legacyCluster = new JedisCluster(CLUSTER_NODES, timeout, MAX_ATTEMPTS, poolConfig);
239+
240+
// New Builder pattern
241+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().timeoutMillis(timeout)
242+
.password(PASSWORD).build();
243+
244+
newCluster = RedisClusterClient.builder().nodes(CLUSTER_NODES).clientConfig(clientConfig)
245+
.maxAttempts(MAX_ATTEMPTS).poolConfig(poolConfig).build();
246+
247+
verifyBothClients(legacyCluster, newCluster);
248+
}
249+
250+
/**
251+
* Test migration from single HostAndPort constructor with poolConfig. Tests constructor:
252+
* JedisCluster(HostAndPort, GenericObjectPoolConfig&lt;Connection&gt;)
253+
*/
254+
@Test
255+
public void testConstructorWithSingleNodeAndPoolConfig() {
256+
HostAndPort singleNode = HostAndPorts.getStableClusterServers().get(0);
257+
GenericObjectPoolConfig<Connection> poolConfig = new ConnectionPoolConfig();
258+
259+
// Legacy constructor with single node
260+
legacyCluster = new JedisCluster(singleNode, poolConfig);
261+
262+
// New Builder pattern - need to add password and wrap single node in a Set
263+
JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().password(PASSWORD).build();
264+
265+
Set<HostAndPort> singleNodeSet = new HashSet<>();
266+
singleNodeSet.add(singleNode);
267+
268+
newCluster = RedisClusterClient.builder().nodes(singleNodeSet).clientConfig(clientConfig)
269+
.poolConfig(poolConfig).build();
270+
271+
verifyBothClients(legacyCluster, newCluster);
272+
}
273+
274+
protected void verifyBothClients(JedisCluster legacyCluster, RedisClusterClient newCluster) {
275+
// Verify both discovered the cluster nodes
276+
assertNotNull(legacyCluster.getClusterNodes(), "Legacy cluster should discover cluster nodes");
277+
assertNotNull(newCluster.getClusterNodes(), "New cluster should discover cluster nodes");
278+
279+
// Both should have discovered the same number of nodes
280+
assertEquals(legacyCluster.getClusterNodes().size(), newCluster.getClusterNodes().size(),
281+
"Both approaches should discover the same number of cluster nodes");
282+
283+
// Test basic string operations
284+
String key1 = "test-string-key";
285+
legacyCluster.set(key1, "value1");
286+
assertEquals("value1", newCluster.get(key1));
287+
288+
// Test increment operations
289+
String key2 = "test-counter-key";
290+
legacyCluster.set(key2, "0");
291+
newCluster.incr(key2);
292+
assertEquals("1", legacyCluster.get(key2));
293+
294+
// Clean up
295+
newCluster.del(key1, key2);
296+
}
297+
298+
/**
299+
* Helper method to clean up cluster data before and after tests.
300+
*/
301+
private void cleanClusterData() {
302+
// Connect to each stable cluster node and flush data
303+
for (HostAndPort node : HostAndPorts.getStableClusterServers()) {
304+
try (redis.clients.jedis.Jedis jedis = new redis.clients.jedis.Jedis(node)) {
305+
jedis.auth(PASSWORD);
306+
jedis.flushDB();
307+
} catch (Exception e) {
308+
// Ignore errors during cleanup
309+
}
310+
}
311+
}
312+
}

0 commit comments

Comments
 (0)