volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/pdb/pdb_test.go (about) 1 /* 2 Copyright 2023 The Volcano Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package pdb 18 19 import ( 20 "reflect" 21 "testing" 22 23 v1 "k8s.io/api/core/v1" 24 pdbPolicy "k8s.io/api/policy/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/client-go/informers" 27 "k8s.io/client-go/kubernetes/fake" 28 "volcano.sh/volcano/pkg/scheduler/api" 29 "volcano.sh/volcano/pkg/scheduler/cache" 30 "volcano.sh/volcano/pkg/scheduler/conf" 31 "volcano.sh/volcano/pkg/scheduler/framework" 32 ) 33 34 const LabelName = "volcano.sh/job-name" 35 36 func TestPreemptableAndReclaimableFn(t *testing.T) { 37 // 1. init task1 and task2 38 task1 := api.NewTaskInfo(makePod("test-pod1", map[string]string{LabelName: "job-1"})) 39 task2 := api.NewTaskInfo(makePod("test-pod2", map[string]string{LabelName: "job-1"})) 40 // 2. init tests 41 // (a. test without pdb 42 // (b. test with pdb, but no tasks can be evicted 43 // (c. test with pdb, but only test1 can be evicted 44 tests := []struct { 45 name string 46 pdbs []*pdbPolicy.PodDisruptionBudget 47 preemptees []*api.TaskInfo 48 expectVictims []*api.TaskInfo 49 expectVictimsMap map[*api.TaskInfo]bool 50 }{{ 51 name: "test without pdbs", 52 pdbs: nil, 53 preemptees: []*api.TaskInfo{task1, task2}, 54 expectVictims: []*api.TaskInfo{task1, task2}, 55 expectVictimsMap: map[*api.TaskInfo]bool{task1: true, task2: true}, 56 }, { 57 name: "test with pdbs(can evict 0 pod)", 58 pdbs: []*pdbPolicy.PodDisruptionBudget{ 59 { 60 ObjectMeta: metav1.ObjectMeta{ 61 Name: "test-pdb", 62 Namespace: "default", 63 }, 64 Spec: pdbPolicy.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{LabelName: "job-1"}}}, 65 Status: pdbPolicy.PodDisruptionBudgetStatus{DisruptionsAllowed: 0}, 66 }, 67 }, 68 preemptees: []*api.TaskInfo{task1, task2}, 69 expectVictims: nil, 70 expectVictimsMap: make(map[*api.TaskInfo]bool), 71 }, { 72 name: "test with pdbs(can evict 1 pod)", 73 pdbs: []*pdbPolicy.PodDisruptionBudget{ 74 { 75 ObjectMeta: metav1.ObjectMeta{ 76 Name: "test-pdb", 77 Namespace: "default", 78 }, 79 Spec: pdbPolicy.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{LabelName: "job-1"}}}, 80 Status: pdbPolicy.PodDisruptionBudgetStatus{DisruptionsAllowed: 1}, 81 }, 82 }, 83 preemptees: []*api.TaskInfo{task1, task2}, 84 expectVictims: []*api.TaskInfo{task1}, 85 expectVictimsMap: map[*api.TaskInfo]bool{task1: true}, 86 }, 87 } 88 89 // 3. set the test plugin name and fns 90 enabled := true 91 pluginOption := conf.PluginOption{ 92 Name: PluginName, 93 EnabledPreemptable: &enabled, 94 EnabledReclaimable: &enabled, 95 EnabledVictim: &enabled, 96 } 97 98 // 4. range every test 99 for _, test := range tests { 100 101 // (a. set the fake informerFactory and add pdbs to pdb informer 102 client := fake.NewSimpleClientset() 103 informerFactory := informers.NewSharedInformerFactory(client, 0) 104 informer := informerFactory.Policy().V1().PodDisruptionBudgets().Informer() 105 for _, pdb := range test.pdbs { 106 informer.GetStore().Add(pdb) 107 } 108 109 // (b. set the SchedulerCache 110 schedulerCache := &cache.SchedulerCache{} 111 schedulerCache.SetSharedInformerFactory(informerFactory) 112 113 // (c. set the Session with preempt, reclaim and shuffle action 114 ssn := framework.OpenSession(schedulerCache, []conf.Tier{ 115 { 116 Plugins: []conf.PluginOption{pluginOption}, 117 }, 118 }, 119 []conf.Configuration{ 120 { 121 Name: "preempt", 122 }, 123 { 124 Name: "reclaim", 125 }, 126 { 127 Name: "shuffle", 128 }, 129 }, 130 ) 131 132 // (d. register actions 133 plugin := &pdbPlugin{} 134 plugin.OnSessionOpen(ssn) // register preempt fn 135 136 // (e. test the Preemptable in pdb plugin 137 victims := ssn.Preemptable(&api.TaskInfo{}, test.preemptees) 138 if !reflect.DeepEqual(test.expectVictims, victims) { 139 t.Errorf("Test of preemptable: test name: %s, expected: %v, got %v ", test.name, test.expectVictims, victims) 140 } 141 142 // (f. test the Reclaimable in pdb plugin 143 victims = ssn.Reclaimable(&api.TaskInfo{}, test.preemptees) 144 if !reflect.DeepEqual(test.expectVictims, victims) { 145 t.Errorf("Test of reclaimable: test name: %s, expected: %v, got %v ", test.name, test.expectVictims, victims) 146 } 147 148 // (g. test the VictimTasks in pdb plugin 149 victimsMap := ssn.VictimTasks(test.preemptees) 150 if !reflect.DeepEqual(test.expectVictimsMap, victimsMap) { 151 t.Errorf("Test of victimTasks: test name %s, expected: %v, got %v ", test.name, test.expectVictims, victims) 152 } 153 } 154 } 155 156 func makePod(name string, labels map[string]string) *v1.Pod { 157 return &v1.Pod{ 158 ObjectMeta: metav1.ObjectMeta{ 159 Name: name, 160 Namespace: "default", 161 Labels: labels, 162 }, 163 Spec: v1.PodSpec{ 164 Containers: []v1.Container{ 165 {}, 166 }, 167 }, 168 } 169 }