CB-554: weight <= 0 excludes a profile from automatic placement, not 1.0
This commit is contained in:
@@ -237,6 +237,105 @@ class PlacementPolicyTest {
|
||||
assertTrue(e.getMessage().contains("1 unreachable"), e.getMessage());
|
||||
}
|
||||
|
||||
// --- CB-554: weight <= 0 excludes a candidate from automatic selection ------------------
|
||||
|
||||
@Test
|
||||
void weightedSkipsWeightZeroProfile() {
|
||||
PlacementPolicy policy = PlacementPolicies.weighted();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 1.0f, null));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertEquals("b", policy.select(ctx(candidates, noSessions())).profile(),
|
||||
"a has weight 0, so every pick lands on b");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void weightedThrowsWhenAllWeightZero() {
|
||||
PlacementPolicy policy = PlacementPolicies.weighted();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 0.0f, null));
|
||||
PlacementException e = assertThrows(PlacementException.class,
|
||||
() -> policy.select(ctx(candidates, noSessions())));
|
||||
assertTrue(e.getMessage().contains("weight 0"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void weightedTreatsNegativeWeightAsExcludedNotError() {
|
||||
PlacementPolicy policy = PlacementPolicies.weighted();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", -1.0f, null),
|
||||
PlacementCandidate.profile("b", 1.0f, null));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertEquals("b", policy.select(ctx(candidates, noSessions())).profile(),
|
||||
"a has a negative weight, so it is excluded like weight 0 — never picked, never an error");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void weightZeroAndQuarantinedIsNotDoubleCounted() {
|
||||
PlacementPolicy policy = PlacementPolicies.weighted();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 1.0f, null),
|
||||
PlacementCandidate.profile("c", 1.0f, null));
|
||||
// a is BOTH weight-0 and quarantined; b and c are quarantined only. If a were counted
|
||||
// into both buckets, "quarantined" would read 3 (or the arithmetic would go negative)
|
||||
// instead of the true count of 2 candidates actually quarantined.
|
||||
PlacementContext mixedCtx = ctx(candidates, noSessions(), Set.of(), Set.of("a", "b", "c"));
|
||||
PlacementException e = assertThrows(PlacementException.class, () -> policy.select(mixedCtx));
|
||||
assertTrue(e.getMessage().contains("1 weight-0"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("2 quarantined"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("0 remaining"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void roundRobinSkipsWeightZeroProfiles() {
|
||||
PlacementPolicy policy = PlacementPolicies.roundRobin();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 1.0f, null));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertEquals("b", policy.select(ctx(candidates, noSessions())).profile(),
|
||||
"a has weight 0, so every pick lands on b");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void roundRobinThrowsWhenAllWeightZero() {
|
||||
PlacementPolicy policy = PlacementPolicies.roundRobin();
|
||||
List<PlacementCandidate> candidates = List.of(
|
||||
PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 0.0f, null));
|
||||
PlacementException e = assertThrows(PlacementException.class,
|
||||
() -> policy.select(ctx(candidates, noSessions())));
|
||||
assertTrue(e.getMessage().contains("weight 0"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fixedSkipsWeightZeroDefault() {
|
||||
PlacementPolicy policy = PlacementPolicies.fixed();
|
||||
PlacementContext ctx = new PlacementContext("b",
|
||||
List.of(PlacementCandidate.profile("a", 1.0f, null),
|
||||
PlacementCandidate.profile("b", 0.0f, null)),
|
||||
noSessions(), Set.of(), Set.of());
|
||||
assertEquals("a", policy.select(ctx).profile(),
|
||||
"the default 'b' has weight 0, so fixed falls through to the first available candidate");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fixedThrowsWhenDefaultAndEveryCandidateWeightZero() {
|
||||
PlacementPolicy policy = PlacementPolicies.fixed();
|
||||
PlacementContext ctx = new PlacementContext("b",
|
||||
List.of(PlacementCandidate.profile("a", 0.0f, null),
|
||||
PlacementCandidate.profile("b", 0.0f, null)),
|
||||
noSessions(), Set.of(), Set.of());
|
||||
PlacementException e = assertThrows(PlacementException.class, () -> policy.select(ctx));
|
||||
assertTrue(e.getMessage().contains("weight 0"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownPolicyNameThrows() {
|
||||
assertThrows(IllegalArgumentException.class, () -> PlacementPolicies.fromName("random"));
|
||||
|
||||
Reference in New Issue
Block a user