Skip to content

Commit f72bd77

Browse files
committed
removed all the optimization parts and implemented only the core WRS logic
Signed-off-by: Jooho Lee <jlee@redhat.com>
1 parent be7ff49 commit f72bd77

File tree

2 files changed

+94
-260
lines changed

2 files changed

+94
-260
lines changed

pkg/epp/scheduling/framework/plugins/picker/picker_test.go

Lines changed: 42 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -143,143 +143,80 @@ func TestPickWeightedRandomPicker(t *testing.T) {
143143
pod4 := &types.PodMetrics{Pod: &backend.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod4"}}}
144144
pod5 := &types.PodMetrics{Pod: &backend.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod5"}}}
145145

146+
// A-Res algorithm uses U^(1/w) transformation which introduces statistical variance
147+
// beyond simple proportional sampling. Generous tolerance is required to prevent
148+
// flaky tests in CI environments, especially for multi-tier weights.
146149
tests := []struct {
147150
name string
148151
input []*types.ScoredPod
149152
maxPods int // maxNumOfEndpoints for this test
150153
iterations int
151154
expectedProbabilities map[string]float64 // pod name -> expected probability
152155
tolerancePercent float64 // acceptable deviation percentage
153-
expectExactLength int // expected exact length per iteration (0 means skip this check)
154156
}{
155-
{
156-
name: "All pods requested - basic functionality",
157-
input: []*types.ScoredPod{
158-
{Pod: pod1, Score: 10},
159-
{Pod: pod2, Score: 20},
160-
{Pod: pod3, Score: 30},
161-
},
162-
maxPods: 5, // Request more than available
163-
iterations: 10,
164-
expectExactLength: 3, // All 3 pods returned (maxPods >= totalPods, so use all)
165-
},
166157
{
167158
name: "High weight dominance test",
168159
input: []*types.ScoredPod{
169-
{Pod: pod1, Score: 10}, // 10/100 = 10%
170-
{Pod: pod2, Score: 90}, // 90/100 = 90%
160+
{Pod: pod1, Score: 10}, // Lower weight
161+
{Pod: pod2, Score: 90}, // Higher weight (should dominate)
171162
},
172-
maxPods: 1, // special case: maxEndpoint=1, totalPods=2 → topN=2 (uses all)
163+
maxPods: 1,
173164
iterations: 2000,
174165
expectedProbabilities: map[string]float64{
175166
"pod1": 0.10,
176167
"pod2": 0.90,
177168
},
178-
tolerancePercent: 20.0, // ±20% (more tolerant for statistical variance)
169+
tolerancePercent: 20.0,
179170
},
180171
{
181-
name: "Equal weights test with topN filtering",
172+
name: "Equal weights test - A-Res uniform distribution",
182173
input: []*types.ScoredPod{
183-
{Pod: pod1, Score: 50}, // Equal scores (will be in top 2 after sorting)
184-
{Pod: pod2, Score: 50}, // Equal scores (will be in top 2 after sorting)
185-
{Pod: pod3, Score: 50}, // Equal scores (will be filtered out)
174+
{Pod: pod1, Score: 100}, // Equal weights (higher values for better numerical precision)
175+
{Pod: pod2, Score: 100}, // Equal weights should yield uniform distribution
176+
{Pod: pod3, Score: 100}, // Equal weights in A-Res
186177
},
187-
maxPods: 1, // ratio = 1/3 = 0.333 < 0.34, so topN = 1+1 = 2
178+
maxPods: 1,
188179
iterations: 1500,
189180
expectedProbabilities: map[string]float64{
190-
"pod1": 0.333, // Each pod has equal chance: 2/3 * 1/2 ≈ 0.333
191-
"pod2": 0.333, // Each pod has equal chance: 2/3 * 1/2 ≈ 0.333
192-
"pod3": 0.333, // Each pod has equal chance: 2/3 * 1/2 ≈ 0.333
193-
},
194-
tolerancePercent: 15.0, // ±15%
195-
},
196-
{
197-
name: "Progressive weight test",
198-
input: []*types.ScoredPod{
199-
{Pod: pod1, Score: 20}, // 20/60 = 33.3%
200-
{Pod: pod2, Score: 40}, // 40/60 = 66.7%
201-
},
202-
maxPods: 1, // special case: maxEndpoint=1, totalPods=2 → topN=2 (uses all)
203-
iterations: 1200,
204-
expectedProbabilities: map[string]float64{
205-
"pod1": 0.333,
206-
"pod2": 0.667,
181+
"pod1": 0.333, // Equal weights should yield uniform distribution
182+
"pod2": 0.333, // A-Res maintains equal probability for equal weights
183+
"pod3": 0.333, // Each pod has theoretically equal chance
207184
},
208-
tolerancePercent: 20.0, // ±20% (more tolerant for statistical variance)
185+
tolerancePercent: 20.0,
209186
},
210187
{
211-
name: "Zero weight exclusion test",
188+
name: "Zero weight exclusion test - A-Res edge case",
212189
input: []*types.ScoredPod{
213-
{Pod: pod1, Score: 30}, // 30/30 = 100%
214-
{Pod: pod2, Score: 0}, // 0/30 = 0%
190+
{Pod: pod1, Score: 30}, // Normal weight, should be selected
191+
{Pod: pod2, Score: 0}, // Zero weight, never selected in A-Res
215192
},
216193
maxPods: 1,
217194
iterations: 500,
218195
expectedProbabilities: map[string]float64{
219-
"pod1": 1.0,
220-
"pod2": 0.0,
196+
"pod1": 1.0, // Only pod with positive weight
197+
"pod2": 0.0, // Zero weight pods are filtered out
221198
},
222-
tolerancePercent: 5.0, // ±5%
199+
tolerancePercent: 5.0, // ±5% tolerance (should be exact for zero weights)
223200
},
224201
{
225-
name: "Top N filtering - only top 2 pods with threshold",
202+
name: "Multi-tier weighted test - A-Res complex distribution",
226203
input: []*types.ScoredPod{
227-
{Pod: pod1, Score: 100}, // Highest probability
228-
{Pod: pod2, Score: 90}, // Second highest probability
229-
{Pod: pod3, Score: 50}, // Should be filtered out
230-
{Pod: pod4, Score: 30}, // Should be filtered out
231-
{Pod: pod5, Score: 10}, // Should be filtered out
204+
{Pod: pod1, Score: 100}, // Highest weight
205+
{Pod: pod2, Score: 90}, // High weight
206+
{Pod: pod3, Score: 50}, // Medium weight
207+
{Pod: pod4, Score: 30}, // Low weight
208+
{Pod: pod5, Score: 20}, // Lowest weight
232209
},
233-
maxPods: 1, // ratio = 1/5 = 0.2 < 0.34, so topN = 1+1 = 2
234-
iterations: 1000,
235-
expectedProbabilities: map[string]float64{
236-
"pod1": 0.526, // 100/(100+90) ≈ 52.6%
237-
"pod2": 0.474, // 90/(100+90) ≈ 47.4%
238-
"pod3": 0.0, // Should never be selected
239-
"pod4": 0.0, // Should never be selected
240-
"pod5": 0.0, // Should never be selected
241-
},
242-
tolerancePercent: 15.0,
243-
},
244-
{
245-
name: "Boundary test: ratio exactly at threshold (1/3 ≈ 0.33)",
246-
input: []*types.ScoredPod{
247-
{Pod: pod1, Score: 100}, // Highest probability
248-
{Pod: pod2, Score: 90}, // Second highest probability
249-
{Pod: pod3, Score: 50}, // Should be included (ratio < 0.34)
250-
},
251-
maxPods: 1, // ratio = 1/3 = 0.333 < 0.34, so topN = 1+1 = 2
210+
maxPods: 1,
252211
iterations: 1000,
253212
expectedProbabilities: map[string]float64{
254-
"pod1": 0.526, // 100/(100+90) ≈ 52.6%
255-
"pod2": 0.474, // 90/(100+90) ≈ 47.4%
256-
"pod3": 0.0, // Should never be selected due to filtering
213+
"pod1": 0.345, // Highest weight gets highest probability
214+
"pod2": 0.310, // High weight gets high probability
215+
"pod3": 0.172, // Medium weight gets medium probability
216+
"pod4": 0.103, // Low weight gets low probability
217+
"pod5": 0.069, // Lowest weight gets lowest probability
257218
},
258-
tolerancePercent: 15.0,
259-
},
260-
{
261-
name: "No filtering: ratio above threshold (2/3 ≈ 0.67)",
262-
input: []*types.ScoredPod{
263-
{Pod: pod1, Score: 100}, // Highest probability
264-
{Pod: pod2, Score: 90}, // Second highest probability
265-
{Pod: pod3, Score: 50}, // Should be included (no filtering)
266-
},
267-
maxPods: 2, // ratio = 2/3 = 0.667 ≥ 0.34, so no topN filtering
268-
iterations: 10,
269-
expectExactLength: 2, // Should return exactly 2 pods per iteration
270-
},
271-
{
272-
name: "Edge case: maxPods > filtered count, should use all pods",
273-
input: []*types.ScoredPod{
274-
{Pod: pod1, Score: 100},
275-
{Pod: pod2, Score: 90},
276-
{Pod: pod3, Score: 50},
277-
{Pod: pod4, Score: 30},
278-
{Pod: pod5, Score: 10},
279-
},
280-
maxPods: 5, // maxPods >= totalPods, so use all 5 pods
281-
iterations: 10,
282-
expectExactLength: 5, // All 5 pods should be returned
219+
tolerancePercent: 25.0,
283220
},
284221
}
285222

@@ -288,45 +225,25 @@ func TestPickWeightedRandomPicker(t *testing.T) {
288225
picker := NewWeightedRandomPicker(test.maxPods)
289226
selectionCounts := make(map[string]int)
290227

291-
// Initialize counters for simple pod names
228+
// Initialize selection counters for each pod
292229
for _, pod := range test.input {
293230
podName := pod.GetPod().NamespacedName.Name
294231
selectionCounts[podName] = 0
295232
}
296233

297-
// Run multiple iterations to gather statistics
298-
var totalLength int
234+
// Run multiple iterations to gather statistical data
299235
for i := 0; i < test.iterations; i++ {
300-
// Create fresh copy of input for each iteration
301-
inputCopy := make([]*types.ScoredPod, len(test.input))
302-
for j, pod := range test.input {
303-
inputCopy[j] = &types.ScoredPod{Pod: pod.Pod, Score: pod.Score}
304-
}
236+
result := picker.Pick(context.Background(), types.NewCycleState(), test.input)
305237

306-
result := picker.Pick(context.Background(), types.NewCycleState(), inputCopy)
307-
totalLength += len(result.TargetPods)
308-
309-
// Count selections for probability distribution (when selecting 1 pod)
310-
if test.maxPods == 1 && len(result.TargetPods) > 0 {
238+
// Count selections for probability analysis
239+
if len(result.TargetPods) > 0 {
311240
selectedPodName := result.TargetPods[0].GetPod().NamespacedName.Name
312241
selectionCounts[selectedPodName]++
313242
}
314243
}
315244

316-
// Check exact length if specified
317-
if test.expectExactLength > 0 {
318-
expectedTotalLength := test.expectExactLength * test.iterations
319-
if totalLength != expectedTotalLength {
320-
t.Errorf("Expected total length %d (avg %.1f), got %d (avg %.1f)",
321-
expectedTotalLength, float64(test.expectExactLength),
322-
totalLength, float64(totalLength)/float64(test.iterations))
323-
} else {
324-
t.Logf("Exact length test passed: %d pods selected per iteration ✓", test.expectExactLength)
325-
}
326-
}
327-
328-
// Verify probability distribution (only for single pod selection tests)
329-
if test.expectedProbabilities != nil && test.maxPods == 1 {
245+
// Verify probability distribution
246+
if test.expectedProbabilities != nil {
330247
for podName, expectedProb := range test.expectedProbabilities {
331248
actualCount := selectionCounts[podName]
332249
actualProb := float64(actualCount) / float64(test.iterations)

0 commit comments

Comments
 (0)