CB-554: weight <= 0 excludes a profile from automatic placement, not 1.0
CI / contract (pull_request) Successful in 44s
CI / build (pull_request) Successful in 52s

This commit is contained in:
Dai Ha
2026-08-15 12:54:02 +02:00
parent 72d3481de3
commit a1f4dc365a
8 changed files with 267 additions and 20 deletions
@@ -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"));