@@ -41,7 +41,13 @@ const (
41
41
42
42
type nodeToScoreMap map [string ]int64
43
43
44
- func initTest (nodeTopologies []* topologyv1alpha2.NodeResourceTopology ) (map [string ]* v1.Node , ctrlclient.Client ) {
44
+ type nrtFilterFn func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology
45
+
46
+ func nrtPassthrough (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
47
+ return nrt
48
+ }
49
+
50
+ func initTest (nodeTopologies []* topologyv1alpha2.NodeResourceTopology , nrtFilter nrtFilterFn ) (map [string ]* v1.Node , ctrlclient.Client ) {
45
51
nodesMap := make (map [string ]* v1.Node )
46
52
47
53
// init node objects
@@ -62,7 +68,12 @@ func initTest(nodeTopologies []*topologyv1alpha2.NodeResourceTopology) (map[stri
62
68
panic (err )
63
69
}
64
70
65
- for _ , obj := range nodeTopologies {
71
+ for _ , obj_ := range nodeTopologies {
72
+ obj := nrtFilter (obj_ )
73
+ if obj == nil {
74
+ continue
75
+ }
76
+
66
77
if err := fakeClient .Create (context .Background (), obj .DeepCopy ()); err != nil {
67
78
panic (err )
68
79
}
@@ -133,7 +144,7 @@ func TestNodeResourceScorePlugin(t *testing.T) {
133
144
}
134
145
135
146
for _ , test := range tests {
136
- nodesMap , lister := initTest (defaultNUMANodes (withPolicy (topologyv1alpha2 .SingleNUMANodeContainerLevel )))
147
+ nodesMap , lister := initTest (defaultNUMANodes (withPolicy (topologyv1alpha2 .SingleNUMANodeContainerLevel )), nrtPassthrough )
137
148
t .Run (test .name , func (t * testing.T ) {
138
149
tm := & TopologyMatch {
139
150
scoreStrategyFunc : test .strategy ,
@@ -170,7 +181,7 @@ func TestNodeResourceScorePlugin(t *testing.T) {
170
181
}
171
182
172
183
if wantScore != gotScore {
173
- t .Errorf ("wrong score for node %q: wanted: %q , got: %d" , gotNode , wantScore , gotScore )
184
+ t .Errorf ("wrong score for node %q: wanted: %d , got: %d" , gotNode , wantScore , gotScore )
174
185
}
175
186
}
176
187
}
@@ -428,7 +439,7 @@ func TestNodeResourceScorePluginLeastNUMA(t *testing.T) {
428
439
429
440
for _ , tc := range testCases {
430
441
t .Run (tc .name , func (t * testing.T ) {
431
- nodesMap , lister := initTest (tc .nodes )
442
+ nodesMap , lister := initTest (tc .nodes , nrtPassthrough )
432
443
433
444
tm := & TopologyMatch {
434
445
scoreStrategyType : apiconfig .LeastNUMANodes ,
@@ -461,6 +472,144 @@ func TestNodeResourceScorePluginLeastNUMA(t *testing.T) {
461
472
}
462
473
}
463
474
475
+ // when only a subset of nodes has NRT data available[1], prefer the nodes which have the NRT data over the other nodes;
476
+ // IOW, a node without NRT data available should always have score == 0
477
+ func TestNodeResourcePartialDataScorePlugin (t * testing.T ) {
478
+ type podRequests struct {
479
+ pod * v1.Pod
480
+ name string
481
+ wantStatus * framework.Status
482
+ }
483
+ pRequests := []podRequests {
484
+ {
485
+ pod : makePodByResourceList (& v1.ResourceList {
486
+ v1 .ResourceCPU : * resource .NewQuantity (2 , resource .DecimalSI ),
487
+ v1 .ResourceMemory : * resource .NewQuantity (20 * 1024 * 1024 , resource .DecimalSI )}),
488
+ name : "Pod1" ,
489
+ wantStatus : nil ,
490
+ },
491
+ }
492
+
493
+ type testScenario struct {
494
+ name string
495
+ wantedRes nodeToScoreMap
496
+ requests []podRequests
497
+ strategy scoreStrategyFn
498
+ nrtFilter nrtFilterFn
499
+ }
500
+
501
+ tests := []testScenario {
502
+ {
503
+ name : "No data at all, MostAllocated strategy" ,
504
+ wantedRes : nodeToScoreMap {},
505
+ requests : pRequests ,
506
+ strategy : mostAllocatedScoreStrategy ,
507
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
508
+ return nil
509
+ },
510
+ },
511
+ {
512
+ name : "No data at all, LeastAllocated strategy" ,
513
+ wantedRes : nodeToScoreMap {},
514
+ requests : pRequests ,
515
+ strategy : leastAllocatedScoreStrategy ,
516
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
517
+ return nil
518
+ },
519
+ },
520
+ {
521
+ name : "No data at all, BalancedAllocation strategy" ,
522
+ wantedRes : nodeToScoreMap {},
523
+ requests : pRequests ,
524
+ strategy : balancedAllocationScoreStrategy ,
525
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
526
+ return nil
527
+ },
528
+ },
529
+ {
530
+ name : "One node with NRT data, MostAllocated strategy" ,
531
+ wantedRes : nodeToScoreMap {"Node1" : 27 },
532
+ requests : pRequests ,
533
+ strategy : mostAllocatedScoreStrategy ,
534
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
535
+ if nrt .Name != "Node1" {
536
+ return nil
537
+ }
538
+ return nrt
539
+ },
540
+ },
541
+ {
542
+ name : "One node with NRT data, LeastAllocated strategy" ,
543
+ wantedRes : nodeToScoreMap {"Node1" : 73 },
544
+ requests : pRequests ,
545
+ strategy : leastAllocatedScoreStrategy ,
546
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
547
+ if nrt .Name != "Node1" {
548
+ return nil
549
+ }
550
+ return nrt
551
+ },
552
+ },
553
+ {
554
+ name : "One node with NRT data, BalancedAllocation strategy" ,
555
+ wantedRes : nodeToScoreMap {"Node1" : 89 },
556
+ requests : pRequests ,
557
+ strategy : balancedAllocationScoreStrategy ,
558
+ nrtFilter : func (nrt * topologyv1alpha2.NodeResourceTopology ) * topologyv1alpha2.NodeResourceTopology {
559
+ if nrt .Name != "Node1" {
560
+ return nil
561
+ }
562
+ return nrt
563
+ },
564
+ },
565
+ }
566
+
567
+ for _ , test := range tests {
568
+ nodesMap , lister := initTest (defaultNUMANodes (withPolicy (topologyv1alpha2 .SingleNUMANodeContainerLevel )), test .nrtFilter )
569
+ t .Run (test .name , func (t * testing.T ) {
570
+ tm := & TopologyMatch {
571
+ scoreStrategyFunc : test .strategy ,
572
+ nrtCache : nrtcache .NewPassthrough (lister ),
573
+ }
574
+
575
+ for _ , req := range test .requests {
576
+ nodeToScore := make (nodeToScoreMap , len (nodesMap ))
577
+ for _ , node := range nodesMap {
578
+ score , gotStatus := tm .Score (
579
+ context .Background (),
580
+ framework .NewCycleState (),
581
+ req .pod ,
582
+ node .ObjectMeta .Name )
583
+
584
+ t .Logf ("%v; %v; %v; score: %v; status: %v\n " ,
585
+ test .name ,
586
+ req .name ,
587
+ node .ObjectMeta .Name ,
588
+ score ,
589
+ gotStatus )
590
+
591
+ if ! reflect .DeepEqual (gotStatus , req .wantStatus ) {
592
+ t .Errorf ("status does not match: %v, want: %v\n " , gotStatus , req .wantStatus )
593
+ }
594
+ nodeToScore [node .ObjectMeta .Name ] = score
595
+ }
596
+ gotNode := findMaxScoreNode (nodeToScore )
597
+ gotScore := nodeToScore [gotNode ]
598
+ t .Logf ("%q: got node %q with score %d\n " , test .name , gotNode , gotScore )
599
+ for wantNode , wantScore := range test .wantedRes {
600
+ if wantNode != gotNode {
601
+ t .Errorf ("failed to select the desired node: wanted: %q, got: %q" , wantNode , gotNode )
602
+ }
603
+
604
+ if wantScore != gotScore {
605
+ t .Errorf ("wrong score for node %q: wanted: %d, got: %d" , gotNode , wantScore , gotScore )
606
+ }
607
+ }
608
+ }
609
+ })
610
+ }
611
+ }
612
+
464
613
// return the name of the node with the highest score
465
614
func findMaxScoreNode (nodeToScore nodeToScoreMap ) string {
466
615
max := int64 (0 )
0 commit comments