@@ -506,6 +506,114 @@ func TestLimitHostsToRequest(t *testing.T) {
506506 }
507507}
508508
509+ func TestShuffleTopHosts (t * testing.T ) {
510+ tests := []struct {
511+ name string
512+ hosts []string
513+ k int
514+ unchangedTailFrom int // index from which hosts should be unchanged (-1 if all can change)
515+ expectUnchanged bool
516+ }{
517+ {
518+ name : "empty hosts returns empty" ,
519+ hosts : []string {},
520+ k : 3 ,
521+ },
522+ {
523+ name : "single host returns unchanged" ,
524+ hosts : []string {"host1" },
525+ k : 3 ,
526+ unchangedTailFrom : 0 ,
527+ },
528+ {
529+ name : "two hosts with k=3 shuffles all" ,
530+ hosts : []string {"host1" , "host2" },
531+ k : 3 ,
532+ unchangedTailFrom : - 1 ,
533+ },
534+ {
535+ name : "three hosts with k=3 shuffles all" ,
536+ hosts : []string {"host1" , "host2" , "host3" },
537+ k : 3 ,
538+ unchangedTailFrom : - 1 ,
539+ },
540+ {
541+ name : "four hosts with k=3 shuffles first 3" ,
542+ hosts : []string {"host1" , "host2" , "host3" , "host4" },
543+ k : 3 ,
544+ unchangedTailFrom : 3 ,
545+ },
546+ {
547+ name : "shuffles only first k hosts" ,
548+ hosts : []string {"host1" , "host2" , "host3" , "host4" , "host5" },
549+ k : 3 ,
550+ unchangedTailFrom : 3 ,
551+ },
552+ {
553+ name : "k=0 disables shuffling" ,
554+ hosts : []string {"host1" , "host2" , "host3" , "host4" , "host5" },
555+ k : 0 ,
556+ expectUnchanged : true ,
557+ },
558+ {
559+ name : "negative k disables shuffling" ,
560+ hosts : []string {"host1" , "host2" , "host3" , "host4" , "host5" },
561+ k : - 1 ,
562+ expectUnchanged : true ,
563+ },
564+ {
565+ name : "k larger than hosts shuffles all" ,
566+ hosts : []string {"host1" , "host2" },
567+ k : 10 ,
568+ unchangedTailFrom : - 1 ,
569+ },
570+ }
571+
572+ for _ , tt := range tests {
573+ t .Run (tt .name , func (t * testing.T ) {
574+ original := make ([]string , len (tt .hosts ))
575+ copy (original , tt .hosts )
576+
577+ result := shuffleTopHosts (tt .hosts , tt .k )
578+
579+ if len (result ) != len (tt .hosts ) {
580+ t .Fatalf ("expected %d hosts, got %d" , len (tt .hosts ), len (result ))
581+ }
582+ // Verify original slice not modified
583+ for i , h := range original {
584+ if tt .hosts [i ] != h {
585+ t .Errorf ("original slice modified at %d: expected %s, got %s" , i , h , tt .hosts [i ])
586+ }
587+ }
588+ // When k <= 0, expect the same slice returned (no copy)
589+ if tt .expectUnchanged {
590+ if len (result ) > 0 && & result [0 ] != & tt .hosts [0 ] {
591+ t .Error ("expected same slice returned when k <= 0" )
592+ }
593+ return
594+ }
595+ // Verify tail unchanged
596+ if tt .unchangedTailFrom >= 0 {
597+ for i := tt .unchangedTailFrom ; i < len (original ); i ++ {
598+ if result [i ] != original [i ] {
599+ t .Errorf ("expected host[%d] = %s unchanged, got %s" , i , original [i ], result [i ])
600+ }
601+ }
602+ }
603+ // Verify all hosts present
604+ hostSet := make (map [string ]bool )
605+ for _ , h := range result {
606+ hostSet [h ] = true
607+ }
608+ for _ , h := range original {
609+ if ! hostSet [h ] {
610+ t .Errorf ("host %s missing from result" , h )
611+ }
612+ }
613+ })
614+ }
615+ }
616+
509617func TestHTTPAPI_inferPipelineName (t * testing.T ) {
510618 delegate := & mockHTTPAPIDelegate {}
511619 api := NewAPI (HTTPAPIConfig {}, delegate ).(* httpAPI )
0 commit comments