ConnectionInitializationContextTest.java
package redis.clients.jedis.mcf;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import redis.clients.jedis.Endpoint;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.mcf.InitializationPolicy.Decision;
/**
* Unit tests for {@link ConnectionInitializationContext}.
*/
@ExtendWith(MockitoExtension.class)
public class ConnectionInitializationContextTest {
@Mock
private HealthStatusManager healthStatusManager;
@Mock
private MultiDbConnectionProvider.Database database1;
@Mock
private MultiDbConnectionProvider.Database database2;
@Mock
private MultiDbConnectionProvider.Database database3;
private Endpoint endpoint1;
private Endpoint endpoint2;
private Endpoint endpoint3;
private Map<Endpoint, MultiDbConnectionProvider.Database> databases;
@BeforeEach
void setUp() {
endpoint1 = new HostAndPort("fake", 6379);
endpoint2 = new HostAndPort("fake", 6380);
endpoint3 = new HostAndPort("fake", 6381);
databases = new HashMap<>();
}
@Nested
@DisplayName("Context Construction Tests")
class ContextConstructionTests {
@Test
@DisplayName("Should count healthy endpoints as available")
void shouldCountHealthyAsAvailable() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.HEALTHY);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(2, ctx.getAvailableConnections());
assertEquals(0, ctx.getFailedConnections());
assertEquals(0, ctx.getPendingConnections());
}
@Test
@DisplayName("Should count unhealthy endpoints as failed")
void shouldCountUnhealthyAsFailed() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.UNHEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.UNHEALTHY);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(0, ctx.getAvailableConnections());
assertEquals(2, ctx.getFailedConnections());
assertEquals(0, ctx.getPendingConnections());
}
@Test
@DisplayName("Should count unknown status as pending")
void shouldCountUnknownAsPending() {
databases.put(endpoint1, database1);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.UNKNOWN);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(0, ctx.getAvailableConnections());
assertEquals(0, ctx.getFailedConnections());
assertEquals(1, ctx.getPendingConnections());
}
@Test
@DisplayName("Should count endpoints without health check as available")
void shouldCountNoHealthCheckAsAvailable() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(false);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(false);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(2, ctx.getAvailableConnections());
assertEquals(0, ctx.getFailedConnections());
assertEquals(0, ctx.getPendingConnections());
}
@Test
@DisplayName("Should handle mixed health check states")
void shouldHandleMixedStates() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
databases.put(endpoint3, database3);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.UNHEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint3)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint3)).thenReturn(HealthStatus.UNKNOWN);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(1, ctx.getAvailableConnections());
assertEquals(1, ctx.getFailedConnections());
assertEquals(1, ctx.getPendingConnections());
}
@Test
@DisplayName("Should handle empty database map")
void shouldHandleEmptyDatabaseMap() {
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(0, ctx.getAvailableConnections());
assertEquals(0, ctx.getFailedConnections());
assertEquals(0, ctx.getPendingConnections());
}
@Test
@DisplayName("Should handle mix of health check enabled and disabled endpoints")
void shouldHandleMixedHealthCheckConfiguration() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
databases.put(endpoint3, database3);
// endpoint1: health check enabled, healthy
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
// endpoint2: health check disabled - should be counted as available
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(false);
// endpoint3: health check enabled, pending
when(healthStatusManager.hasHealthCheck(endpoint3)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint3)).thenReturn(HealthStatus.UNKNOWN);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(2, ctx.getAvailableConnections()); // endpoint1 + endpoint2
assertEquals(0, ctx.getFailedConnections());
assertEquals(1, ctx.getPendingConnections()); // endpoint3
}
}
@Nested
@DisplayName("ConformsTo Policy Evaluation Tests")
class ConformsToPolicyTests {
@Test
@DisplayName("Should delegate to policy evaluate method")
void shouldDelegateToPolicy() {
databases.put(endpoint1, database1);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(Decision.SUCCESS, ctx.conformsTo(InitializationPolicy.BuiltIn.ONE_AVAILABLE));
assertEquals(Decision.SUCCESS, ctx.conformsTo(InitializationPolicy.BuiltIn.ALL_AVAILABLE));
assertEquals(Decision.SUCCESS,
ctx.conformsTo(InitializationPolicy.BuiltIn.MAJORITY_AVAILABLE));
}
@Test
@DisplayName("Should return CONTINUE for ONE_AVAILABLE when all pending")
void shouldReturnContinueWhenAllPending() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.UNKNOWN);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.UNKNOWN);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(Decision.CONTINUE, ctx.conformsTo(InitializationPolicy.BuiltIn.ONE_AVAILABLE));
}
@Test
@DisplayName("Should return FAIL for ALL_AVAILABLE when any failed")
void shouldReturnFailWhenAnyFailed() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.UNHEALTHY);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
assertEquals(Decision.FAIL, ctx.conformsTo(InitializationPolicy.BuiltIn.ALL_AVAILABLE));
}
}
@Nested
@DisplayName("ToString Tests")
class ToStringTests {
@Test
@DisplayName("Should include counts in toString")
void shouldIncludeCountsInToString() {
databases.put(endpoint1, database1);
databases.put(endpoint2, database2);
databases.put(endpoint3, database3);
when(healthStatusManager.hasHealthCheck(endpoint1)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint1)).thenReturn(HealthStatus.HEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint2)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint2)).thenReturn(HealthStatus.UNHEALTHY);
when(healthStatusManager.hasHealthCheck(endpoint3)).thenReturn(true);
when(healthStatusManager.getHealthStatus(endpoint3)).thenReturn(HealthStatus.UNKNOWN);
ConnectionInitializationContext ctx = new ConnectionInitializationContext(databases,
healthStatusManager);
String result = ctx.toString();
assertTrue(result.contains("available=1"));
assertTrue(result.contains("failed=1"));
assertTrue(result.contains("pending=1"));
}
}
}