volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/drf/hdrf_test.go (about) 1 package drf 2 3 import ( 4 "flag" 5 "fmt" 6 "reflect" 7 "testing" 8 9 "github.com/agiledragon/gomonkey/v2" 10 v1 "k8s.io/api/core/v1" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/client-go/tools/record" 13 "k8s.io/klog/v2" 14 15 schedulingv1 "volcano.sh/apis/pkg/apis/scheduling/v1beta1" 16 "volcano.sh/volcano/cmd/scheduler/app/options" 17 "volcano.sh/volcano/pkg/scheduler/actions/allocate" 18 "volcano.sh/volcano/pkg/scheduler/api" 19 "volcano.sh/volcano/pkg/scheduler/cache" 20 "volcano.sh/volcano/pkg/scheduler/conf" 21 "volcano.sh/volcano/pkg/scheduler/framework" 22 "volcano.sh/volcano/pkg/scheduler/plugins/proportion" 23 "volcano.sh/volcano/pkg/scheduler/util" 24 ) 25 26 func makePods(num int, cpu, mem, podGroupName string) []*v1.Pod { 27 pods := []*v1.Pod{} 28 for i := 0; i < num; i++ { 29 pods = append(pods, util.BuildPod("default", 30 fmt.Sprintf("%s-p%d", podGroupName, i), "", 31 v1.PodPending, api.BuildResourceList(cpu, mem), 32 podGroupName, make(map[string]string), make(map[string]string))) 33 } 34 return pods 35 } 36 37 type queueSpec struct { 38 name string 39 hierarchy string 40 weights string 41 } 42 43 type pgSpec struct { 44 taskNum int 45 cpu string 46 mem string 47 pg string 48 queue string 49 } 50 51 func TestHDRF(t *testing.T) { 52 klog.InitFlags(nil) 53 flag.Set("v", "4") 54 flag.Set("alsologtostderr", "true") 55 var tmp *cache.SchedulerCache 56 patches := gomonkey.ApplyMethod(reflect.TypeOf(tmp), "AddBindTask", func(scCache *cache.SchedulerCache, task *api.TaskInfo) error { 57 scCache.Binder.Bind(nil, []*api.TaskInfo{task}) 58 return nil 59 }) 60 defer patches.Reset() 61 62 patchUpdateQueueStatus := gomonkey.ApplyMethod(reflect.TypeOf(tmp), "UpdateQueueStatus", func(scCache *cache.SchedulerCache, queue *api.QueueInfo) error { 63 return nil 64 }) 65 defer patchUpdateQueueStatus.Reset() 66 67 s := options.NewServerOption() 68 s.MinNodesToFind = 100 69 s.PercentageOfNodesToFind = 100 70 s.RegisterOptions() 71 72 framework.RegisterPluginBuilder(PluginName, New) 73 framework.RegisterPluginBuilder("proportion", proportion.New) 74 defer framework.CleanupPluginBuilders() 75 76 tests := []struct { 77 name string 78 pgSpecs []pgSpec 79 nodes []*v1.Node 80 queues []*schedulingv1.Queue 81 queueSpecs []queueSpec 82 expected map[string]*api.Resource 83 }{ 84 { 85 name: "rescaling test", 86 pgSpecs: []pgSpec{ 87 { 88 taskNum: 10, 89 cpu: "1", 90 mem: "1G", 91 pg: "pg1", 92 queue: "root-sci", 93 }, 94 { 95 taskNum: 10, 96 cpu: "1", 97 mem: "0G", 98 pg: "pg21", 99 queue: "root-eng-dev", 100 }, 101 { 102 taskNum: 10, 103 cpu: "0", 104 mem: "1G", 105 pg: "pg22", 106 queue: "root-eng-prod", 107 }, 108 }, 109 nodes: []*v1.Node{util.BuildNode("n", 110 api.BuildResourceList("10", "10G", []api.ScalarResource{{Name: "pods", Value: "50"}}...), 111 make(map[string]string))}, 112 queueSpecs: []queueSpec{ 113 { 114 name: "root-sci", 115 hierarchy: "root/sci", 116 weights: "100/50", 117 }, 118 { 119 name: "root-eng-dev", 120 hierarchy: "root/eng/dev", 121 weights: "100/50/50", 122 }, 123 { 124 name: "root-eng-prod", 125 hierarchy: "root/eng/prod", 126 weights: "100/50/50", 127 }, 128 }, 129 expected: map[string]*api.Resource{ 130 "pg1": { 131 MilliCPU: 5000, 132 Memory: 5000000000, 133 ScalarResources: map[v1.ResourceName]float64{"pods": 5}, 134 }, 135 "pg21": { 136 MilliCPU: 5000, 137 Memory: 0, 138 ScalarResources: map[v1.ResourceName]float64{"pods": 5}, 139 }, 140 "pg22": { 141 MilliCPU: 0, 142 Memory: 5000000000, 143 ScalarResources: map[v1.ResourceName]float64{"pods": 5}, 144 }, 145 }, 146 }, 147 { 148 name: "blocking nodes test", 149 pgSpecs: []pgSpec{ 150 { 151 taskNum: 30, 152 cpu: "1", 153 mem: "0G", 154 pg: "pg1", 155 queue: "root-pg1", 156 }, 157 { 158 taskNum: 30, 159 cpu: "1", 160 mem: "0G", 161 pg: "pg2", 162 queue: "root-pg2", 163 }, 164 { 165 taskNum: 30, 166 cpu: "1", 167 mem: "0G", 168 pg: "pg31", 169 queue: "root-pg3-pg31", 170 }, 171 { 172 taskNum: 30, 173 cpu: "0", 174 mem: "1G", 175 pg: "pg32", 176 queue: "root-pg3-pg32", 177 }, 178 { 179 taskNum: 30, 180 cpu: "0", 181 mem: "1G", 182 pg: "pg4", 183 queue: "root-pg4", 184 }, 185 }, 186 nodes: []*v1.Node{util.BuildNode("n", 187 api.BuildResourceList("30", "30G", []api.ScalarResource{{Name: "pods", Value: "500"}}...), 188 make(map[string]string))}, 189 queueSpecs: []queueSpec{ 190 { 191 name: "root-pg1", 192 hierarchy: "root/pg1", 193 weights: "100/25", 194 }, 195 { 196 name: "root-pg2", 197 hierarchy: "root/pg2", 198 weights: "100/25", 199 }, 200 { 201 name: "root-pg3-pg31", 202 hierarchy: "root/pg3/pg31", 203 weights: "100/25/50", 204 }, 205 { 206 name: "root-pg3-pg32", 207 hierarchy: "root/pg3/pg32", 208 weights: "100/25/50", 209 }, 210 { 211 name: "root-pg4", 212 hierarchy: "root/pg4", 213 weights: "100/25", 214 }, 215 }, 216 expected: map[string]*api.Resource{ 217 218 "pg1": { 219 MilliCPU: 10000, 220 Memory: 0, 221 ScalarResources: map[v1.ResourceName]float64{"pods": 10}, 222 }, 223 "pg": { 224 MilliCPU: 10000, 225 Memory: 0, 226 ScalarResources: map[v1.ResourceName]float64{"pods": 10}, 227 }, 228 "pg31": { 229 MilliCPU: 10000, 230 Memory: 0, 231 ScalarResources: map[v1.ResourceName]float64{"pods": 10}, 232 }, 233 "pg32": { 234 MilliCPU: 0, 235 Memory: 15000000000, 236 ScalarResources: map[v1.ResourceName]float64{"pods": 15}, 237 }, 238 "pg4": { 239 MilliCPU: 0, 240 Memory: 15000000000, 241 ScalarResources: map[v1.ResourceName]float64{"pods": 15}, 242 }, 243 }, 244 }, 245 } 246 for _, test := range tests { 247 if test.name == "blocking nodes test" { 248 // TODO(wangyang0616): First make sure that ut can run, and then fix the failed ut later 249 // See issue for details: https://github.com/volcano-sh/volcano/issues/2810 250 t.Skip("Test cases are not as expected, fixed later. see issue: #2810") 251 } 252 253 binder := &util.FakeBinder{ 254 Binds: map[string]string{}, 255 Channel: make(chan string, 300), 256 } 257 schedulerCache := &cache.SchedulerCache{ 258 Nodes: make(map[string]*api.NodeInfo), 259 Jobs: make(map[api.JobID]*api.JobInfo), 260 Queues: make(map[api.QueueID]*api.QueueInfo), 261 Binder: binder, 262 StatusUpdater: &util.FakeStatusUpdater{}, 263 VolumeBinder: &util.FakeVolumeBinder{}, 264 Recorder: record.NewFakeRecorder(100), 265 } 266 for _, node := range test.nodes { 267 schedulerCache.AddOrUpdateNode(node) 268 } 269 for _, q := range test.queueSpecs { 270 schedulerCache.AddQueueV1beta1( 271 &schedulingv1.Queue{ 272 ObjectMeta: metav1.ObjectMeta{ 273 Name: q.name, 274 Annotations: map[string]string{ 275 schedulingv1.KubeHierarchyAnnotationKey: q.hierarchy, 276 schedulingv1.KubeHierarchyWeightAnnotationKey: q.weights, 277 }, 278 }, 279 Spec: schedulingv1.QueueSpec{ 280 Weight: 1, 281 }, 282 }) 283 } 284 for _, pgSpec := range test.pgSpecs { 285 pods := makePods(pgSpec.taskNum, pgSpec.cpu, pgSpec.mem, pgSpec.pg) 286 for _, pod := range pods { 287 schedulerCache.AddPod(pod) 288 } 289 schedulerCache.AddPodGroupV1beta1(&schedulingv1.PodGroup{ 290 ObjectMeta: metav1.ObjectMeta{ 291 Name: pgSpec.pg, 292 Namespace: "default", 293 }, 294 Spec: schedulingv1.PodGroupSpec{ 295 Queue: pgSpec.queue, 296 }, 297 Status: schedulingv1.PodGroupStatus{ 298 Phase: schedulingv1.PodGroupInqueue, 299 }, 300 }) 301 } 302 trueValue := true 303 ssn := framework.OpenSession(schedulerCache, []conf.Tier{ 304 { 305 Plugins: []conf.PluginOption{ 306 { 307 Name: PluginName, 308 EnabledHierarchy: &trueValue, 309 EnabledQueueOrder: &trueValue, 310 EnabledJobOrder: &trueValue, 311 }, 312 { 313 Name: "proportion", 314 EnabledJobEnqueued: &trueValue, 315 EnabledQueueOrder: &trueValue, 316 EnabledReclaimable: &trueValue, 317 }, 318 }, 319 }, 320 }, nil) 321 defer framework.CloseSession(ssn) 322 allocateAction := allocate.New() 323 324 allocateAction.Execute(ssn) 325 326 for _, job := range ssn.Jobs { 327 if reflect.DeepEqual(test.expected, job.Allocated) { 328 t.Fatalf("%s: job %s expected resource %s, but got %s", test.name, job.Name, test.expected[job.Name], job.Allocated) 329 } 330 } 331 332 } 333 }