Skip to content

Commit 5c9c8cc

Browse files
committed
refactor test case
1 parent e62968f commit 5c9c8cc

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

cluster-autoscaler/processors/customresources/gpu_processor_test.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package customresources
1818

1919
import (
2020
"fmt"
21+
"slices"
22+
"strings"
2123
"testing"
2224
"time"
2325

@@ -27,6 +29,7 @@ import (
2729
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2830
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
2931
testprovider "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/test"
32+
"k8s.io/autoscaler/cluster-autoscaler/context"
3033
ca_context "k8s.io/autoscaler/cluster-autoscaler/context"
3134
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
3235
)
@@ -399,3 +402,246 @@ func TestFilterOutNodesWithUnreadyResourcesDRA(t *testing.T) {
399402
}
400403
}
401404
}
405+
406+
type testCase struct { // Maps keyed by node name
407+
allNodes map[string]*apiv1.Node
408+
readyNodes []*apiv1.Node
409+
wantNodesWithUnreadyOverride []string
410+
}
411+
412+
func TestFilterOutNodesWithUnreadyResourcesRefactor(t *testing.T) {
413+
start := time.Now()
414+
later := start.Add(10 * time.Minute)
415+
// Any non-zero resource quantity value on a Ready node indicates GPU is ready.
416+
resourceQuantityOne := *resource.NewQuantity(1, resource.DecimalSI)
417+
// A zero resource quantity value on a Ready node indicates GPU is unready.
418+
resourceQuantityZero := *resource.NewQuantity(0, resource.DecimalSI)
419+
readyCondition := apiv1.NodeCondition{
420+
Type: apiv1.NodeReady,
421+
Status: apiv1.ConditionTrue,
422+
LastTransitionTime: metav1.NewTime(later),
423+
}
424+
unreadyCondition := apiv1.NodeCondition{
425+
Type: apiv1.NodeReady,
426+
Status: apiv1.ConditionFalse,
427+
LastTransitionTime: metav1.NewTime(later),
428+
}
429+
cases := []testCase{
430+
{
431+
allNodes: map[string]*apiv1.Node{
432+
"nodeGpuReady": {
433+
ObjectMeta: metav1.ObjectMeta{
434+
Name: "nodeGpuReady",
435+
Labels: gpuLabels,
436+
CreationTimestamp: metav1.NewTime(start),
437+
},
438+
Status: apiv1.NodeStatus{
439+
Capacity: apiv1.ResourceList{
440+
gpu.ResourceNvidiaGPU: resourceQuantityOne,
441+
},
442+
Allocatable: apiv1.ResourceList{
443+
gpu.ResourceNvidiaGPU: resourceQuantityOne,
444+
},
445+
Conditions: []apiv1.NodeCondition{readyCondition},
446+
},
447+
},
448+
"nodeGpuReadyDRA": {
449+
ObjectMeta: metav1.ObjectMeta{
450+
Name: "nodeGpuReadyDRA",
451+
CreationTimestamp: metav1.NewTime(start),
452+
},
453+
Status: apiv1.NodeStatus{
454+
Conditions: []apiv1.NodeCondition{readyCondition},
455+
},
456+
},
457+
"nodeDirectXReady": {
458+
ObjectMeta: metav1.ObjectMeta{
459+
Name: "nodeDirectXReady",
460+
Labels: gpuLabels,
461+
CreationTimestamp: metav1.NewTime(start),
462+
},
463+
Status: apiv1.NodeStatus{
464+
Capacity: apiv1.ResourceList{
465+
gpu.ResourceDirectX: resourceQuantityOne,
466+
},
467+
Allocatable: apiv1.ResourceList{
468+
gpu.ResourceDirectX: resourceQuantityOne,
469+
},
470+
Conditions: []apiv1.NodeCondition{readyCondition},
471+
},
472+
},
473+
"nodeVanillaReady": {
474+
ObjectMeta: metav1.ObjectMeta{
475+
Name: "nodeVanillaReady",
476+
Labels: make(map[string]string),
477+
CreationTimestamp: metav1.NewTime(start),
478+
},
479+
Status: apiv1.NodeStatus{
480+
Conditions: []apiv1.NodeCondition{readyCondition},
481+
},
482+
},
483+
"nodeGpuUnready": {
484+
ObjectMeta: metav1.ObjectMeta{
485+
Name: "nodeGpuUnready",
486+
Labels: gpuLabels,
487+
CreationTimestamp: metav1.NewTime(start),
488+
},
489+
Status: apiv1.NodeStatus{
490+
Capacity: apiv1.ResourceList{
491+
gpu.ResourceNvidiaGPU: resourceQuantityZero,
492+
},
493+
Allocatable: apiv1.ResourceList{
494+
gpu.ResourceNvidiaGPU: resourceQuantityZero,
495+
},
496+
Conditions: []apiv1.NodeCondition{readyCondition},
497+
},
498+
},
499+
"nodeDirectXUnready": {
500+
ObjectMeta: metav1.ObjectMeta{
501+
Name: "nodeDirectXUnready",
502+
Labels: gpuLabels,
503+
CreationTimestamp: metav1.NewTime(start),
504+
},
505+
Status: apiv1.NodeStatus{
506+
Capacity: apiv1.ResourceList{
507+
gpu.ResourceDirectX: resourceQuantityZero,
508+
},
509+
Allocatable: apiv1.ResourceList{
510+
gpu.ResourceDirectX: resourceQuantityZero,
511+
},
512+
Conditions: []apiv1.NodeCondition{readyCondition},
513+
},
514+
},
515+
"nodeGpuUnready2": {
516+
ObjectMeta: metav1.ObjectMeta{
517+
Name: "nodeGpuUnready2",
518+
Labels: gpuLabels,
519+
CreationTimestamp: metav1.NewTime(start),
520+
},
521+
Status: apiv1.NodeStatus{
522+
Conditions: []apiv1.NodeCondition{readyCondition},
523+
},
524+
},
525+
"nodeVanillaNotReady": {
526+
ObjectMeta: metav1.ObjectMeta{
527+
Name: "nodeVanillaNotReady",
528+
Labels: make(map[string]string),
529+
CreationTimestamp: metav1.NewTime(start),
530+
},
531+
Status: apiv1.NodeStatus{
532+
Conditions: []apiv1.NodeCondition{unreadyCondition},
533+
},
534+
},
535+
},
536+
readyNodes: []*apiv1.Node{
537+
{
538+
ObjectMeta: metav1.ObjectMeta{
539+
Name: "nodeGpuReady",
540+
Labels: gpuLabels,
541+
CreationTimestamp: metav1.NewTime(start),
542+
},
543+
Status: apiv1.NodeStatus{
544+
Capacity: apiv1.ResourceList{
545+
gpu.ResourceNvidiaGPU: resourceQuantityOne,
546+
},
547+
Allocatable: apiv1.ResourceList{
548+
gpu.ResourceNvidiaGPU: resourceQuantityOne,
549+
},
550+
Conditions: []apiv1.NodeCondition{readyCondition},
551+
},
552+
},
553+
{
554+
ObjectMeta: metav1.ObjectMeta{
555+
Name: "nodeGpuReadyDRA",
556+
CreationTimestamp: metav1.NewTime(start),
557+
},
558+
Status: apiv1.NodeStatus{
559+
Conditions: []apiv1.NodeCondition{readyCondition},
560+
},
561+
},
562+
{
563+
ObjectMeta: metav1.ObjectMeta{
564+
Name: "nodeDirectXReady",
565+
Labels: gpuLabels,
566+
CreationTimestamp: metav1.NewTime(start),
567+
},
568+
Status: apiv1.NodeStatus{
569+
Capacity: apiv1.ResourceList{
570+
gpu.ResourceDirectX: resourceQuantityOne,
571+
},
572+
Allocatable: apiv1.ResourceList{
573+
gpu.ResourceDirectX: resourceQuantityOne,
574+
},
575+
Conditions: []apiv1.NodeCondition{readyCondition},
576+
},
577+
},
578+
{
579+
ObjectMeta: metav1.ObjectMeta{
580+
Name: "nodeVanillaReady",
581+
Labels: make(map[string]string),
582+
CreationTimestamp: metav1.NewTime(start),
583+
},
584+
Status: apiv1.NodeStatus{
585+
Conditions: []apiv1.NodeCondition{readyCondition},
586+
},
587+
},
588+
},
589+
wantNodesWithUnreadyOverride: []string{
590+
"nodeGpuUnready",
591+
"nodeDirectXUnready",
592+
"nodeGpuUnready2",
593+
},
594+
},
595+
}
596+
597+
nodeGpuConfig := func(node *apiv1.Node) *cloudprovider.GpuConfig {
598+
var draDriverName string
599+
if strings.Contains(node.Name, "DRA") {
600+
draDriverName = "gpu.nvidia.com"
601+
}
602+
return &cloudprovider.GpuConfig{
603+
ExtendedResourceName: "",
604+
DraDriverName: draDriverName,
605+
}
606+
}
607+
provider := testprovider.NewTestCloudProviderBuilder().WithNodeGpuConfig(nodeGpuConfig).Build()
608+
609+
for _, tc := range cases {
610+
processor := GpuCustomResourcesProcessor{}
611+
autoscalingCtx := &ca_context.AutoscalingContext{CloudProvider: provider}
612+
gotAllNodes, gotReadyNodes := processor.FilterOutNodesWithUnreadyResources(autoscalingCtx, toList(tc.allNodes), tc.readyNodes, nil)
613+
gotAllNodesSet := toSet(gotAllNodes)
614+
for _, v := range tc.allNodes {
615+
if _, found := gotAllNodesSet[v.Name]; !found {
616+
t.Errorf("FilterOutNodesWithUnreadyResources() missing node %v from all nodes list", v.Name)
617+
}
618+
if v.Status.Conditions[0].Status == apiv1.ConditionTrue && gotAllNodesSet[v.Name].Status.Conditions[0].Status == apiv1.ConditionFalse {
619+
assert.Contains(t, tc.wantNodesWithUnreadyOverride, v.Name, fmt.Sprintf("FilterOutNodesWithUnreadyResources() node %v status condition is unready, but was not expected to be", v.Name))
620+
assert.Len(t, gotAllNodesSet[v.Name].Status.Conditions, 1, fmt.Sprintf("FilterOutNodesWithUnreadyResources() node %v status conditions count does not match expected", v.Name))
621+
assert.Equal(t, v.ObjectMeta, gotAllNodesSet[v.Name].ObjectMeta, fmt.Sprintf("FilterOutNodesWithUnreadyResources() node %v metadata does not match expected", v.Name))
622+
}
623+
}
624+
assert.Equal(t, gotReadyNodes, tc.readyNodes, fmt.Sprintf("FilterOutNodesWithUnreadyResources() node %v in ready nodes list does not match expected", gotReadyNodes))
625+
for _, v := range gotAllNodesSet {
626+
if !slices.Contains(tc.wantNodesWithUnreadyOverride, v.Name) {
627+
assert.Equal(t, v, tc.allNodes[v.Name], fmt.Sprintf("FilterOutNodesWithUnreadyResources() node %v in all nodes list does not match expected", v.Name))
628+
}
629+
}
630+
}
631+
}
632+
633+
func toList(m map[string]*apiv1.Node) []*apiv1.Node {
634+
var l []*apiv1.Node
635+
for _, n := range m {
636+
l = append(l, n)
637+
}
638+
return l
639+
}
640+
641+
func toSet(l []*apiv1.Node) map[string]*apiv1.Node {
642+
m := make(map[string]*apiv1.Node)
643+
for _, n := range l {
644+
m[n.Name] = n
645+
}
646+
return m
647+
}

0 commit comments

Comments
 (0)