InitializationPolicyTest.java
package redis.clients.jedis.mcf;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.mcf.InitializationPolicy.Decision;
import redis.clients.jedis.mcf.InitializationPolicy.InitializationContext;
/**
* Unit tests for {@link InitializationPolicy} implementations.
* <p>
* Tests verify the decision logic for different combinations of available, failed, and pending
* connections for each built-in policy:
* <ul>
* <li>{@link InitializationPolicy.BuiltIn#ALL_AVAILABLE}</li>
* <li>{@link InitializationPolicy.BuiltIn#MAJORITY_AVAILABLE}</li>
* <li>{@link InitializationPolicy.BuiltIn#ONE_AVAILABLE}</li>
* </ul>
*/
@DisplayName("InitializationPolicy Unit Tests")
public class InitializationPolicyTest {
/**
* Test implementation of InitializationContext for unit testing.
*/
private static class TestContext implements InitializationContext {
private final int available;
private final int failed;
private final int pending;
TestContext(int available, int failed, int pending) {
this.available = available;
this.failed = failed;
this.pending = pending;
}
@Override
public int getAvailableConnections() {
return available;
}
@Override
public int getFailedConnections() {
return failed;
}
@Override
public int getPendingConnections() {
return pending;
}
}
@Nested
@DisplayName("ALL_AVAILABLE Policy Tests")
class AllAvailablePolicyTests {
private final InitializationPolicy policy = InitializationPolicy.BuiltIn.ALL_AVAILABLE;
@Test
@DisplayName("Should return SUCCESS when all connections are available")
void shouldSucceedWhenAllAvailable() {
TestContext ctx = new TestContext(3, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS when single connection is available and no others")
void shouldSucceedWithSingleConnection() {
TestContext ctx = new TestContext(1, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when no connections configured (0,0,0)")
void shouldFailWithEmptyContext() {
TestContext ctx = new TestContext(0, 0, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when any connection fails")
void shouldFailWhenAnyConnectionFails() {
TestContext ctx = new TestContext(2, 1, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when all connections fail")
void shouldFailWhenAllConnectionsFail() {
TestContext ctx = new TestContext(0, 3, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when single connection fails")
void shouldFailWithSingleFailure() {
TestContext ctx = new TestContext(0, 1, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL immediately when any failure even with pending")
void shouldFailImmediatelyWithAnyFailure() {
TestContext ctx = new TestContext(1, 1, 2);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when connections are pending")
void shouldContinueWhenPending() {
TestContext ctx = new TestContext(2, 0, 1);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when all connections are pending")
void shouldContinueWhenAllPending() {
TestContext ctx = new TestContext(0, 0, 5);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
}
@Nested
@DisplayName("MAJORITY_AVAILABLE Policy Tests")
class MajorityAvailablePolicyTests {
private final InitializationPolicy policy = InitializationPolicy.BuiltIn.MAJORITY_AVAILABLE;
@Test
@DisplayName("Should return SUCCESS when majority is reached (3 of 5)")
void shouldSucceedWithMajority() {
TestContext ctx = new TestContext(3, 1, 1);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS when all are available")
void shouldSucceedWhenAllAvailable() {
TestContext ctx = new TestContext(5, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS with exact majority (2 of 3)")
void shouldSucceedWithExactMajority() {
TestContext ctx = new TestContext(2, 1, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS with single connection out of one")
void shouldSucceedWithSingleConnection() {
TestContext ctx = new TestContext(1, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS early when majority reached with pending (3 of 5)")
void shouldSucceedEarlyWithMajority() {
TestContext ctx = new TestContext(3, 0, 2);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS early when majority reached (2 of 3, 1 pending)")
void shouldSucceedEarlyWithMajorityOf3() {
TestContext ctx = new TestContext(2, 0, 1);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should handle even number of connections (3 of 4)")
void shouldHandleEvenNumberOfConnections() {
TestContext ctx = new TestContext(3, 1, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should handle two connections (2 of 2)")
void shouldHandleTwoConnections() {
TestContext ctx = new TestContext(2, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS with large number of connections (51 of 100)")
void shouldSucceedWithLargeNumberOfConnections() {
TestContext ctx = new TestContext(51, 49, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when no connections configured (0,0,0)")
void shouldFailWithEmptyContext() {
TestContext ctx = new TestContext(0, 0, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when majority is impossible (2 failed of 3)")
void shouldFailWhenMajorityImpossible() {
TestContext ctx = new TestContext(0, 2, 1);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when all connections fail")
void shouldFailWhenAllFail() {
TestContext ctx = new TestContext(0, 5, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when single database fails")
void shouldFailWithSingleDatabaseFailed() {
TestContext ctx = new TestContext(0, 1, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when majority not reached and no pending (1 of 3)")
void shouldFailWhenMajorityNotReachedNoPending() {
TestContext ctx = new TestContext(1, 2, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL early when majority impossible with pending (1,3,1)")
void shouldFailEarlyWhenMajorityImpossibleWithPending() {
TestContext ctx = new TestContext(1, 3, 1);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL early when majority impossible (3 failed of 5, 2 pending)")
void shouldFailEarlyWhenMajorityImpossible() {
TestContext ctx = new TestContext(0, 3, 2);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should fail with even split (2 of 4)")
void shouldFailWithEvenSplit() {
TestContext ctx = new TestContext(2, 2, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should fail with one of two connections")
void shouldFailWithOneOfTwo() {
TestContext ctx = new TestContext(1, 1, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when majority possible but not yet reached")
void shouldContinueWhenMajorityPossible() {
TestContext ctx = new TestContext(1, 1, 3);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when all pending")
void shouldContinueWhenAllPending() {
TestContext ctx = new TestContext(0, 0, 5);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when below majority with pending (2 of 4)")
void shouldContinueBelowMajority() {
TestContext ctx = new TestContext(2, 0, 2);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE with one available and one pending (1,0,1)")
void shouldContinueWithOneAvailableOnePending() {
TestContext ctx = new TestContext(1, 0, 1);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when majority still possible (1,1,1)")
void shouldContinueWhenMajorityStillPossible() {
TestContext ctx = new TestContext(1, 1, 1);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
}
@Nested
@DisplayName("ONE_AVAILABLE Policy Tests")
class OneAvailablePolicyTests {
private final InitializationPolicy policy = InitializationPolicy.BuiltIn.ONE_AVAILABLE;
@Test
@DisplayName("Should return SUCCESS when one connection is available")
void shouldSucceedWithOneAvailable() {
TestContext ctx = new TestContext(1, 2, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS when all connections are available")
void shouldSucceedWhenAllAvailable() {
TestContext ctx = new TestContext(5, 0, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS early with one available and pending")
void shouldSucceedEarlyWithOneAvailable() {
TestContext ctx = new TestContext(1, 0, 4);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return SUCCESS with multiple available")
void shouldSucceedWithMultipleAvailable() {
TestContext ctx = new TestContext(3, 2, 0);
assertEquals(Decision.SUCCESS, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when no connections configured (0,0,0)")
void shouldFailWithEmptyContext() {
TestContext ctx = new TestContext(0, 0, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when all connections fail")
void shouldFailWhenAllFail() {
TestContext ctx = new TestContext(0, 5, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return FAIL when single connection fails")
void shouldFailWithSingleFailure() {
TestContext ctx = new TestContext(0, 1, 0);
assertEquals(Decision.FAIL, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when all connections are pending")
void shouldContinueWhenAllPending() {
TestContext ctx = new TestContext(0, 0, 5);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
@Test
@DisplayName("Should return CONTINUE when some failed but some pending")
void shouldContinueWithFailedAndPending() {
TestContext ctx = new TestContext(0, 2, 3);
assertEquals(Decision.CONTINUE, policy.evaluate(ctx));
}
}
}