PingStrategyIntegrationTest.java
package redis.clients.jedis.mcf;
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.model.ToxicDirection;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
import redis.clients.jedis.DefaultJedisClientConfig;
import redis.clients.jedis.EndpointConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.HostAndPorts;
import redis.clients.jedis.JedisClientConfig;
import redis.clients.jedis.exceptions.JedisException;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.*;
@Tag("failover")
public class PingStrategyIntegrationTest {
private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("redis-failover-1");
private static final HostAndPort proxyHostAndPort = endpoint.getHostAndPort();
private static final ToxiproxyClient tp = new ToxiproxyClient("localhost", 8474);
private static Proxy redisProxy;
@BeforeAll
public static void setupProxy() throws IOException {
if (tp.getProxyOrNull("redis-health-test") != null) {
tp.getProxy("redis-health-test").delete();
}
redisProxy = tp.createProxy("redis-health-test", "0.0.0.0:29379", "redis-failover-1:9379");
}
@AfterAll
public static void cleanupProxy() throws IOException {
if (redisProxy != null) {
redisProxy.delete();
}
}
@BeforeEach
public void resetProxy() throws IOException {
redisProxy.enable();
redisProxy.toxics().getAll().forEach(toxic -> {
try {
toxic.remove();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
@Test
public void testPingStrategyRecoversAfterDisconnect() throws Exception {
JedisClientConfig config = DefaultJedisClientConfig.builder().socketTimeoutMillis(1000)
.connectionTimeoutMillis(1000).build();
try (PingStrategy strategy = new PingStrategy(proxyHostAndPort, config,
HealthCheckStrategy.Config.create())) {
// Initial health check should work
HealthStatus initialStatus = strategy.doHealthCheck(proxyHostAndPort);
assertEquals(HealthStatus.HEALTHY, initialStatus);
// Disable the proxy to simulate network failure
redisProxy.disable();
// Health check should now fail - this will expose the bug
assertThrows(JedisException.class, () -> strategy.doHealthCheck(proxyHostAndPort));
// Re-enable proxy
redisProxy.enable();
// Health check should recover
HealthStatus statusAfterEnable = strategy.doHealthCheck(proxyHostAndPort);
assertEquals(HealthStatus.HEALTHY, statusAfterEnable);
}
}
@Test
public void testPingStrategyWithConnectionTimeout() throws Exception {
JedisClientConfig config = DefaultJedisClientConfig.builder().socketTimeoutMillis(100)
.connectionTimeoutMillis(100).build();
try (PingStrategy strategy = new PingStrategy(proxyHostAndPort, config,
HealthCheckStrategy.Config.builder().interval(1000).timeout(500).numProbes(1).build())) {
// Initial health check should work
assertEquals(HealthStatus.HEALTHY, strategy.doHealthCheck(proxyHostAndPort));
// Add latency toxic to simulate slow network
redisProxy.toxics().latency("slow-connection", ToxicDirection.DOWNSTREAM, 1000);
// Health check should timeout and return unhealthy
assertThrows(JedisException.class, () -> strategy.doHealthCheck(proxyHostAndPort));
// Remove toxic
redisProxy.toxics().get("slow-connection").remove();
// Health check should recover
HealthStatus recoveredStatus = strategy.doHealthCheck(proxyHostAndPort);
assertEquals(HealthStatus.HEALTHY, recoveredStatus,
"Health check should recover from high latency");
}
}
@Test
public void testConnectionDropDuringHealthCheck() throws Exception {
JedisClientConfig config = DefaultJedisClientConfig.builder().socketTimeoutMillis(2000).build();
try (PingStrategy strategy = new PingStrategy(proxyHostAndPort, config,
HealthCheckStrategy.Config.create())) {
// Initial health check
assertEquals(HealthStatus.HEALTHY, strategy.doHealthCheck(proxyHostAndPort));
// Simulate connection drop by limiting data transfer
redisProxy.toxics().limitData("connection-drop", ToxicDirection.UPSTREAM, 10);
// This should fail due to connection issues
assertThrows(JedisException.class, () -> strategy.doHealthCheck(proxyHostAndPort));
// Remove toxic
redisProxy.toxics().get("connection-drop").remove();
// Health check should recover
HealthStatus afterRecovery = strategy.doHealthCheck(proxyHostAndPort);
assertEquals(HealthStatus.HEALTHY, afterRecovery);
}
}
}