RedisClusterTestBase.java
package redis.clients.jedis.tls;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import io.redis.test.annotations.ConditionalOnEnv;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import redis.clients.jedis.DefaultJedisClientConfig;
import redis.clients.jedis.EndpointConfig;
import redis.clients.jedis.Endpoints;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.HostAndPortMapper;
import redis.clients.jedis.RedisClusterClient;
import redis.clients.jedis.SslOptions;
import redis.clients.jedis.util.*;
/**
* Abstract base class for SSL/TLS Redis cluster tests.
* <p>
* This class provides common setup and teardown for TLS-enabled Redis cluster tests, including
* truststore initialization and cluster client configuration.
* <p>
* Uses the {@code cluster-stable-tls} endpoint for stable integration tests.
* <p>
* Note: The {@link RedisVersionCondition} and {@link EnabledOnCommandCondition} extensions use the
* non-TLS {@code cluster-stable} endpoint for version/command checks because JUnit 5 extensions run
* before {@code @BeforeAll} methods where the truststore is configured.
*/
@ConditionalOnEnv(value = TestEnvUtil.ENV_OSS_SOURCE, enabled = false)
public abstract class RedisClusterTestBase {
private static final String ENDPOINT_NAME = "cluster-stable-tls";
/**
* Non-TLS endpoint used for version and command checks. Extensions run before @BeforeAll, so we
* can't use TLS endpoints for these checks since the truststore isn't configured yet.
*/
private static final String VERSION_CHECK_ENDPOINT_NAME = "cluster-stable";
private static final String TRUSTSTORE_PASSWORD = "changeit";
@RegisterExtension
public static EnvCondition envCondition = new EnvCondition();
@RegisterExtension
public EnabledOnCommandCondition enabledOnCommandCondition = new EnabledOnCommandCondition(
() -> Endpoints.getRedisEndpoint(VERSION_CHECK_ENDPOINT_NAME));
protected static EndpointConfig tlsEndpoint;
protected static Path trustStorePath;
protected RedisClusterClient cluster;
/**
* HostAndPortMapper that maps IP addresses (127.0.0.1) to localhost for hostname verification.
*/
protected final HostAndPortMapper hostAndPortMap = (HostAndPort hostAndPort) -> {
String host = hostAndPort.getHost();
int port = hostAndPort.getPort();
if ("127.0.0.1".equals(host)) {
host = "localhost";
}
return new HostAndPort(host, port);
};
/**
* HostAndPortMapper that only maps localhost, leaving IP addresses unchanged. Useful for testing
* hostname verification failures.
*/
protected final HostAndPortMapper portMap = (HostAndPort hostAndPort) -> {
if ("localhost".equals(hostAndPort.getHost())) {
return hostAndPort;
}
return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort());
};
@BeforeAll
public static void prepareEndpointAndTrustStore() {
tlsEndpoint = Endpoints.getRedisEndpoint(ENDPOINT_NAME);
List<Path> trustedCertLocation = Collections
.singletonList(tlsEndpoint.getCertificatesLocation());
trustStorePath = TlsUtil.createAndSaveTestTruststore(RedisClusterTestBase.class.getSimpleName(),
trustedCertLocation, TRUSTSTORE_PASSWORD);
TlsUtil.setCustomTrustStore(trustStorePath, TRUSTSTORE_PASSWORD);
}
@AfterAll
public static void teardownTrustStore() {
TlsUtil.restoreOriginalTrustStore();
}
@BeforeEach
public void setUp() {
SslOptions sslOptions = SslOptions.builder().truststore(trustStorePath.toFile())
.trustStoreType("jceks").build();
cluster = RedisClusterClient.builder().nodes(new HashSet<>(tlsEndpoint.getHostsAndPorts()))
.clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword())
.sslOptions(sslOptions).hostAndPortMapper(hostAndPortMap).build())
.build();
cluster.flushAll();
}
@AfterEach
public void tearDown() {
if (cluster != null) {
cluster.flushAll();
cluster.close();
}
}
protected static SslOptions createSslOptions() {
return SslOptions.builder().truststore(trustStorePath.toFile()).trustStoreType("jceks").build();
}
}