Skip to content

Commit 6f1896a

Browse files
committed
test: nil target and validation tests for lb policy
1 parent fbe649e commit 6f1896a

2 files changed

Lines changed: 490 additions & 0 deletions

File tree

pkg/activator/net/lb_policy_test.go

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,269 @@ func TestRoundRobin(t *testing.T) {
260260
})
261261
}
262262

263+
func TestLeastConnectionsPolicy(t *testing.T) {
264+
t.Run("empty trackers", func(t *testing.T) {
265+
cb, pt := leastConnectionsPolicy(context.Background(), []*podTracker{})
266+
defer cb()
267+
if pt != nil {
268+
t.Fatal("Expected nil tracker for empty input")
269+
}
270+
})
271+
272+
t.Run("single tracker", func(t *testing.T) {
273+
podTrackers := makeTrackers(1, 1)
274+
cb, pt := leastConnectionsPolicy(context.Background(), podTrackers)
275+
defer cb()
276+
if pt == nil {
277+
t.Fatal("Expected non-nil tracker")
278+
}
279+
if got, want := pt.dest, podTrackers[0].dest; got != want {
280+
t.Errorf("pt.dest = %s, want: %s", got, want)
281+
}
282+
})
283+
284+
t.Run("multiple trackers with different loads", func(t *testing.T) {
285+
podTrackers := makeTrackers(3, 2)
286+
// Simulate different loads
287+
podTrackers[0].weight.Store(5)
288+
podTrackers[1].weight.Store(2)
289+
podTrackers[2].weight.Store(8)
290+
291+
cb, pt := leastConnectionsPolicy(context.Background(), podTrackers)
292+
defer cb()
293+
if pt == nil {
294+
t.Fatal("Expected non-nil tracker")
295+
}
296+
// Should pick the one with lowest weight (index 1)
297+
if got, want := pt.dest, podTrackers[1].dest; got != want {
298+
t.Errorf("pt.dest = %s, want: %s (should pick lowest load)", got, want)
299+
}
300+
})
301+
302+
t.Run("nil trackers in list", func(t *testing.T) {
303+
podTrackers := []*podTracker{
304+
nil,
305+
{
306+
dest: "tracker-1",
307+
b: queue.NewBreaker(queue.BreakerParams{
308+
QueueDepth: 1,
309+
MaxConcurrency: 1,
310+
InitialCapacity: 1,
311+
}),
312+
},
313+
nil,
314+
}
315+
cb, pt := leastConnectionsPolicy(context.Background(), podTrackers)
316+
defer cb()
317+
if pt == nil {
318+
t.Fatal("Expected non-nil tracker")
319+
}
320+
if got, want := pt.dest, "tracker-1"; got != want {
321+
t.Errorf("pt.dest = %s, want: %s", got, want)
322+
}
323+
})
324+
325+
t.Run("all nil trackers", func(t *testing.T) {
326+
podTrackers := []*podTracker{nil, nil, nil}
327+
cb, pt := leastConnectionsPolicy(context.Background(), podTrackers)
328+
defer cb()
329+
if pt != nil {
330+
t.Fatal("Expected nil tracker when all trackers are nil")
331+
}
332+
})
333+
334+
t.Run("negative weight handling", func(t *testing.T) {
335+
podTrackers := makeTrackers(2, 1)
336+
podTrackers[0].weight.Store(-5)
337+
podTrackers[1].weight.Store(3)
338+
339+
cb, pt := leastConnectionsPolicy(context.Background(), podTrackers)
340+
defer cb()
341+
if pt == nil {
342+
t.Fatal("Expected non-nil tracker")
343+
}
344+
// Negative weight should be treated as 0, so should pick first tracker
345+
if got, want := pt.dest, podTrackers[0].dest; got != want {
346+
t.Errorf("pt.dest = %s, want: %s (negative weight should be treated as 0)", got, want)
347+
}
348+
})
349+
}
350+
351+
func TestRandomLBPolicyWithNilTrackers(t *testing.T) {
352+
t.Run("empty trackers", func(t *testing.T) {
353+
cb, pt := randomLBPolicy(context.Background(), []*podTracker{})
354+
defer cb()
355+
if pt != nil {
356+
t.Fatal("Expected nil tracker for empty input")
357+
}
358+
})
359+
360+
t.Run("all nil trackers", func(t *testing.T) {
361+
podTrackers := []*podTracker{nil, nil, nil}
362+
cb, pt := randomLBPolicy(context.Background(), podTrackers)
363+
defer cb()
364+
if pt != nil {
365+
t.Fatal("Expected nil tracker when all trackers are nil")
366+
}
367+
})
368+
369+
t.Run("mixed nil and valid trackers", func(t *testing.T) {
370+
podTrackers := makeTrackers(3, 0)
371+
// Set middle one to nil
372+
podTrackers[1] = nil
373+
374+
// Run multiple times to ensure we don't get nil
375+
for i := 0; i < 10; i++ {
376+
cb, pt := randomLBPolicy(context.Background(), podTrackers)
377+
defer cb()
378+
if pt == nil {
379+
t.Fatal("Should not return nil when valid trackers exist")
380+
}
381+
if pt.dest != podTrackers[0].dest && pt.dest != podTrackers[2].dest {
382+
t.Fatal("Should return one of the valid trackers")
383+
}
384+
}
385+
})
386+
}
387+
388+
func TestRandomChoice2PolicyWithNilTrackers(t *testing.T) {
389+
t.Run("single nil tracker", func(t *testing.T) {
390+
podTrackers := []*podTracker{nil}
391+
cb, pt := randomChoice2Policy(context.Background(), podTrackers)
392+
defer cb()
393+
if pt != nil {
394+
t.Fatal("Expected nil tracker when single tracker is nil")
395+
}
396+
})
397+
398+
t.Run("all nil trackers", func(t *testing.T) {
399+
podTrackers := []*podTracker{nil, nil, nil}
400+
cb, pt := randomChoice2Policy(context.Background(), podTrackers)
401+
defer cb()
402+
if pt != nil {
403+
t.Fatal("Expected nil tracker when all trackers are nil")
404+
}
405+
})
406+
407+
t.Run("mixed nil and valid trackers", func(t *testing.T) {
408+
podTrackers := makeTrackers(4, 0)
409+
// Set some to nil
410+
podTrackers[1] = nil
411+
podTrackers[3] = nil
412+
413+
// Run multiple times to check behavior
414+
foundNonNil := false
415+
for i := 0; i < 20; i++ {
416+
cb, pt := randomChoice2Policy(context.Background(), podTrackers)
417+
defer cb()
418+
if pt != nil {
419+
foundNonNil = true
420+
if pt.dest != podTrackers[0].dest && pt.dest != podTrackers[2].dest {
421+
t.Fatal("Should return one of the valid trackers")
422+
}
423+
}
424+
}
425+
if !foundNonNil {
426+
t.Fatal("Should find at least one non-nil tracker in multiple attempts")
427+
}
428+
})
429+
430+
t.Run("mostly nil trackers", func(t *testing.T) {
431+
// Create a large array with mostly nils
432+
podTrackers := make([]*podTracker, 10)
433+
// Create a proper tracker with initialized fields
434+
validTracker := &podTracker{
435+
dest: "valid-tracker",
436+
}
437+
// Initialize the weight field properly
438+
validTracker.weight.Store(0)
439+
podTrackers[0] = validTracker
440+
441+
// Run multiple times - should eventually find the valid tracker
442+
foundValid := false
443+
for i := 0; i < 100; i++ {
444+
cb, pt := randomChoice2Policy(context.Background(), podTrackers)
445+
if cb != nil {
446+
defer cb()
447+
}
448+
if pt != nil && pt.dest == "valid-tracker" {
449+
foundValid = true
450+
break
451+
}
452+
}
453+
if !foundValid {
454+
t.Fatal("Should eventually find the valid tracker")
455+
}
456+
})
457+
}
458+
459+
func TestFirstAvailableWithNilTrackers(t *testing.T) {
460+
t.Run("nil trackers in list", func(t *testing.T) {
461+
podTrackers := []*podTracker{
462+
nil,
463+
{
464+
dest: "tracker-1",
465+
b: queue.NewBreaker(queue.BreakerParams{
466+
QueueDepth: 1,
467+
MaxConcurrency: 1,
468+
InitialCapacity: 1,
469+
}),
470+
},
471+
nil,
472+
}
473+
cb, pt := firstAvailableLBPolicy(context.Background(), podTrackers)
474+
defer cb()
475+
if pt == nil {
476+
t.Fatal("Expected non-nil tracker")
477+
}
478+
if got, want := pt.dest, "tracker-1"; got != want {
479+
t.Errorf("pt.dest = %s, want: %s", got, want)
480+
}
481+
})
482+
483+
t.Run("all nil trackers", func(t *testing.T) {
484+
podTrackers := []*podTracker{nil, nil, nil}
485+
cb, pt := firstAvailableLBPolicy(context.Background(), podTrackers)
486+
defer cb()
487+
if pt != nil {
488+
t.Fatal("Expected nil tracker when all trackers are nil")
489+
}
490+
})
491+
}
492+
493+
func TestRoundRobinWithNilTrackers(t *testing.T) {
494+
t.Run("nil trackers in list", func(t *testing.T) {
495+
rrp := newRoundRobinPolicy()
496+
podTrackers := makeTrackers(3, 1)
497+
// Set middle tracker to nil
498+
podTrackers[1] = nil
499+
500+
cb, pt := rrp(context.Background(), podTrackers)
501+
t.Cleanup(cb)
502+
if got, want := pt, podTrackers[0]; got != want {
503+
t.Fatalf("Tracker = %v, want: %v", got, want)
504+
}
505+
506+
// Should skip nil tracker and go to next valid one
507+
cb, pt = rrp(context.Background(), podTrackers)
508+
t.Cleanup(cb)
509+
if got, want := pt, podTrackers[2]; got != want {
510+
t.Fatalf("Tracker = %v, want: %v (should skip nil tracker)", got, want)
511+
}
512+
})
513+
514+
t.Run("all nil trackers", func(t *testing.T) {
515+
rrp := newRoundRobinPolicy()
516+
podTrackers := []*podTracker{nil, nil, nil}
517+
518+
cb, pt := rrp(context.Background(), podTrackers)
519+
defer cb()
520+
if pt != nil {
521+
t.Fatal("Expected nil tracker when all trackers are nil")
522+
}
523+
})
524+
}
525+
263526
func BenchmarkPolicy(b *testing.B) {
264527
for _, test := range []struct {
265528
name string
@@ -276,6 +539,9 @@ func BenchmarkPolicy(b *testing.B) {
276539
}, {
277540
name: "round-robin",
278541
policy: newRoundRobinPolicy(),
542+
}, {
543+
name: "least-connections",
544+
policy: leastConnectionsPolicy,
279545
}} {
280546
for _, n := range []int{1, 2, 3, 10, 100} {
281547
b.Run(fmt.Sprintf("%s-%d-trackers-sequential", test.name, n), func(b *testing.B) {

0 commit comments

Comments
 (0)