k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes 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 noderesources 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 "github.com/stretchr/testify/assert" 26 v1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/util/validation/field" 28 "k8s.io/klog/v2/ktesting" 29 "k8s.io/kubernetes/pkg/scheduler/apis/config" 30 "k8s.io/kubernetes/pkg/scheduler/framework" 31 plfeature "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" 32 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper" 33 "k8s.io/kubernetes/pkg/scheduler/framework/runtime" 34 "k8s.io/kubernetes/pkg/scheduler/internal/cache" 35 st "k8s.io/kubernetes/pkg/scheduler/testing" 36 tf "k8s.io/kubernetes/pkg/scheduler/testing/framework" 37 ) 38 39 func TestRequestedToCapacityRatioScoringStrategy(t *testing.T) { 40 shape := []config.UtilizationShapePoint{ 41 {Utilization: 0, Score: 10}, 42 {Utilization: 100, Score: 0}, 43 } 44 45 tests := []struct { 46 name string 47 requestedPod *v1.Pod 48 nodes []*v1.Node 49 existingPods []*v1.Pod 50 expectedScores framework.NodeScoreList 51 resources []config.ResourceSpec 52 shape []config.UtilizationShapePoint 53 wantErrs field.ErrorList 54 }{ 55 { 56 name: "nothing scheduled, nothing requested (default - least requested nodes have priority)", 57 requestedPod: st.MakePod().Obj(), 58 nodes: []*v1.Node{ 59 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 60 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 61 }, 62 existingPods: []*v1.Pod{ 63 st.MakePod().Node("node1").Obj(), 64 st.MakePod().Node("node1").Obj(), 65 }, 66 expectedScores: []framework.NodeScore{{Name: "node1", Score: framework.MaxNodeScore}, {Name: "node2", Score: framework.MaxNodeScore}}, 67 resources: defaultResources, 68 shape: shape, 69 }, 70 { 71 name: "nothing scheduled, resources requested, differently sized nodes (default - least requested nodes have priority)", 72 requestedPod: st.MakePod(). 73 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 74 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 75 Obj(), 76 nodes: []*v1.Node{ 77 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 78 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 79 }, 80 existingPods: []*v1.Pod{ 81 st.MakePod().Node("node1").Obj(), 82 st.MakePod().Node("node1").Obj(), 83 }, 84 expectedScores: []framework.NodeScore{{Name: "node1", Score: 38}, {Name: "node2", Score: 50}}, 85 resources: defaultResources, 86 shape: shape, 87 }, 88 { 89 name: "no resources requested, pods scheduled with resources (default - least requested nodes have priority)", 90 requestedPod: st.MakePod().Obj(), 91 nodes: []*v1.Node{ 92 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 93 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 94 }, 95 existingPods: []*v1.Pod{ 96 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 97 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 98 }, 99 expectedScores: []framework.NodeScore{{Name: "node1", Score: 38}, {Name: "node2", Score: 50}}, 100 resources: defaultResources, 101 shape: shape, 102 }, 103 } 104 105 for _, test := range tests { 106 t.Run(test.name, func(t *testing.T) { 107 _, ctx := ktesting.NewTestContext(t) 108 ctx, cancel := context.WithCancel(ctx) 109 defer cancel() 110 111 state := framework.NewCycleState() 112 snapshot := cache.NewSnapshot(test.existingPods, test.nodes) 113 fh, _ := runtime.NewFramework(ctx, nil, nil, runtime.WithSnapshotSharedLister(snapshot)) 114 115 p, err := NewFit(ctx, &config.NodeResourcesFitArgs{ 116 ScoringStrategy: &config.ScoringStrategy{ 117 Type: config.RequestedToCapacityRatio, 118 Resources: test.resources, 119 RequestedToCapacityRatio: &config.RequestedToCapacityRatioParam{ 120 Shape: shape, 121 }, 122 }, 123 }, fh, plfeature.Features{}) 124 125 if diff := cmp.Diff(test.wantErrs.ToAggregate(), err, ignoreBadValueDetail); diff != "" { 126 t.Fatalf("got err (-want,+got):\n%s", diff) 127 } 128 if err != nil { 129 return 130 } 131 132 var gotScores framework.NodeScoreList 133 for _, n := range test.nodes { 134 status := p.(framework.PreScorePlugin).PreScore(ctx, state, test.requestedPod, tf.BuildNodeInfos(test.nodes)) 135 if !status.IsSuccess() { 136 t.Errorf("PreScore is expected to return success, but didn't. Got status: %v", status) 137 } 138 score, status := p.(framework.ScorePlugin).Score(ctx, state, test.requestedPod, n.Name) 139 if !status.IsSuccess() { 140 t.Errorf("Score is expected to return success, but didn't. Got status: %v", status) 141 } 142 gotScores = append(gotScores, framework.NodeScore{Name: n.Name, Score: score}) 143 } 144 145 if diff := cmp.Diff(test.expectedScores, gotScores); diff != "" { 146 t.Errorf("Unexpected nodes (-want,+got):\n%s", diff) 147 } 148 }) 149 } 150 } 151 152 func TestBrokenLinearFunction(t *testing.T) { 153 type Assertion struct { 154 p int64 155 expected int64 156 } 157 type Test struct { 158 points []helper.FunctionShapePoint 159 assertions []Assertion 160 } 161 162 tests := []Test{ 163 { 164 points: []helper.FunctionShapePoint{{Utilization: 10, Score: 1}, {Utilization: 90, Score: 9}}, 165 assertions: []Assertion{ 166 {p: -10, expected: 1}, 167 {p: 0, expected: 1}, 168 {p: 9, expected: 1}, 169 {p: 10, expected: 1}, 170 {p: 15, expected: 1}, 171 {p: 19, expected: 1}, 172 {p: 20, expected: 2}, 173 {p: 89, expected: 8}, 174 {p: 90, expected: 9}, 175 {p: 99, expected: 9}, 176 {p: 100, expected: 9}, 177 {p: 110, expected: 9}, 178 }, 179 }, 180 { 181 points: []helper.FunctionShapePoint{{Utilization: 0, Score: 2}, {Utilization: 40, Score: 10}, {Utilization: 100, Score: 0}}, 182 assertions: []Assertion{ 183 {p: -10, expected: 2}, 184 {p: 0, expected: 2}, 185 {p: 20, expected: 6}, 186 {p: 30, expected: 8}, 187 {p: 40, expected: 10}, 188 {p: 70, expected: 5}, 189 {p: 100, expected: 0}, 190 {p: 110, expected: 0}, 191 }, 192 }, 193 { 194 points: []helper.FunctionShapePoint{{Utilization: 0, Score: 2}, {Utilization: 40, Score: 2}, {Utilization: 100, Score: 2}}, 195 assertions: []Assertion{ 196 {p: -10, expected: 2}, 197 {p: 0, expected: 2}, 198 {p: 20, expected: 2}, 199 {p: 30, expected: 2}, 200 {p: 40, expected: 2}, 201 {p: 70, expected: 2}, 202 {p: 100, expected: 2}, 203 {p: 110, expected: 2}, 204 }, 205 }, 206 } 207 208 for i, test := range tests { 209 t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) { 210 function := helper.BuildBrokenLinearFunction(test.points) 211 for _, assertion := range test.assertions { 212 assert.InDelta(t, assertion.expected, function(assertion.p), 0.1, "points=%v, p=%d", test.points, assertion.p) 213 } 214 }) 215 } 216 } 217 218 func TestResourceBinPackingSingleExtended(t *testing.T) { 219 extendedResource1 := map[string]int64{ 220 "intel.com/foo": 4, 221 } 222 extendedResource2 := map[string]int64{ 223 "intel.com/foo": 8, 224 } 225 extendedResource3 := map[v1.ResourceName]string{ 226 "intel.com/foo": "2", 227 } 228 extendedResource4 := map[v1.ResourceName]string{ 229 "intel.com/foo": "4", 230 } 231 232 tests := []struct { 233 pod *v1.Pod 234 pods []*v1.Pod 235 nodes []*v1.Node 236 expectedScores framework.NodeScoreList 237 name string 238 }{ 239 { 240 // Node1 Score = Node2 Score = 0 as the incoming Pod doesn't request extended resource. 241 pod: st.MakePod().Obj(), 242 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResource2), makeNode("node2", 4000, 10000*1024*1024, extendedResource1)}, 243 expectedScores: []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: 0}}, 244 name: "nothing scheduled, nothing requested", 245 }, 246 { 247 // Node1 scores (used resources) on 0-MaxNodeScore scale 248 // Node1 Score: 249 // rawScoringFunction(used + requested / available) 250 // resourceScoringFunction((0+2),8) 251 // = 2/8 * maxUtilization = 25 = rawScoringFunction(25) 252 // Node1 Score: 2 253 // Node2 scores (used resources) on 0-MaxNodeScore scale 254 // rawScoringFunction(used + requested / available) 255 // resourceScoringFunction((0+2),4) 256 // = 2/4 * maxUtilization = 50 = rawScoringFunction(50) 257 // Node2 Score: 5 258 pod: st.MakePod().Req(extendedResource3).Obj(), 259 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResource2), makeNode("node2", 4000, 10000*1024*1024, extendedResource1)}, 260 expectedScores: []framework.NodeScore{{Name: "node1", Score: 2}, {Name: "node2", Score: 5}}, 261 name: "resources requested, pods scheduled with less resources", 262 pods: []*v1.Pod{st.MakePod().Obj()}, 263 }, 264 { 265 // Node1 scores (used resources) on 0-MaxNodeScore scale 266 // Node1 Score: 267 // rawScoringFunction(used + requested / available) 268 // resourceScoringFunction((0+2),8) 269 // = 2/8 * maxUtilization = 25 = rawScoringFunction(25) 270 // Node1 Score: 2 271 // Node2 scores (used resources) on 0-MaxNodeScore scale 272 // rawScoringFunction(used + requested / available) 273 // resourceScoringFunction((2+2),4) 274 // = 4/4 * maxUtilization = maxUtilization = rawScoringFunction(maxUtilization) 275 // Node2 Score: 10 276 pod: st.MakePod().Req(extendedResource3).Obj(), 277 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResource2), makeNode("node2", 4000, 10000*1024*1024, extendedResource1)}, 278 expectedScores: []framework.NodeScore{{Name: "node1", Score: 2}, {Name: "node2", Score: 10}}, 279 name: "resources requested, pods scheduled with resources, on node with existing pod running ", 280 pods: []*v1.Pod{st.MakePod().Req(extendedResource3).Node("node2").Obj()}, 281 }, 282 { 283 // Node1 scores (used resources) on 0-MaxNodeScore scale 284 // Node1 Score: 285 // rawScoringFunction(used + requested / available) 286 // resourceScoringFunction((0+4),8) 287 // = 4/8 * maxUtilization = 50 = rawScoringFunction(50) 288 // Node1 Score: 5 289 // Node2 scores (used resources) on 0-MaxNodeScore scale 290 // rawScoringFunction(used + requested / available) 291 // resourceScoringFunction((0+4),4) 292 // = 4/4 * maxUtilization = maxUtilization = rawScoringFunction(maxUtilization) 293 // Node2 Score: 10 294 pod: st.MakePod().Req(extendedResource4).Obj(), 295 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResource2), makeNode("node2", 4000, 10000*1024*1024, extendedResource1)}, 296 expectedScores: []framework.NodeScore{{Name: "node1", Score: 5}, {Name: "node2", Score: 10}}, 297 name: "resources requested, pods scheduled with more resources", 298 pods: []*v1.Pod{ 299 st.MakePod().Obj(), 300 }, 301 }, 302 } 303 304 for _, test := range tests { 305 t.Run(test.name, func(t *testing.T) { 306 state := framework.NewCycleState() 307 snapshot := cache.NewSnapshot(test.pods, test.nodes) 308 _, ctx := ktesting.NewTestContext(t) 309 fh, _ := runtime.NewFramework(ctx, nil, nil, runtime.WithSnapshotSharedLister(snapshot)) 310 args := config.NodeResourcesFitArgs{ 311 ScoringStrategy: &config.ScoringStrategy{ 312 Type: config.RequestedToCapacityRatio, 313 Resources: []config.ResourceSpec{ 314 {Name: "intel.com/foo", Weight: 1}, 315 }, 316 RequestedToCapacityRatio: &config.RequestedToCapacityRatioParam{ 317 Shape: []config.UtilizationShapePoint{ 318 {Utilization: 0, Score: 0}, 319 {Utilization: 100, Score: 1}, 320 }, 321 }, 322 }, 323 } 324 p, err := NewFit(ctx, &args, fh, plfeature.Features{}) 325 if err != nil { 326 t.Fatalf("unexpected error: %v", err) 327 } 328 329 var gotList framework.NodeScoreList 330 for _, n := range test.nodes { 331 status := p.(framework.PreScorePlugin).PreScore(context.Background(), state, test.pod, tf.BuildNodeInfos(test.nodes)) 332 if !status.IsSuccess() { 333 t.Errorf("PreScore is expected to return success, but didn't. Got status: %v", status) 334 } 335 score, status := p.(framework.ScorePlugin).Score(context.Background(), state, test.pod, n.Name) 336 if !status.IsSuccess() { 337 t.Errorf("Score is expected to return success, but didn't. Got status: %v", status) 338 } 339 gotList = append(gotList, framework.NodeScore{Name: n.Name, Score: score}) 340 } 341 342 if diff := cmp.Diff(test.expectedScores, gotList); diff != "" { 343 t.Errorf("Unexpected nodescore list (-want,+got):\n%s", diff) 344 } 345 }) 346 } 347 } 348 349 func TestResourceBinPackingMultipleExtended(t *testing.T) { 350 extendedResources1 := map[string]int64{ 351 "intel.com/foo": 4, 352 "intel.com/bar": 8, 353 } 354 extendedResources2 := map[string]int64{ 355 "intel.com/foo": 8, 356 "intel.com/bar": 4, 357 } 358 359 extendedResourcePod1 := map[v1.ResourceName]string{ 360 "intel.com/foo": "2", 361 "intel.com/bar": "2", 362 } 363 extendedResourcePod2 := map[v1.ResourceName]string{ 364 "intel.com/foo": "4", 365 "intel.com/bar": "2", 366 } 367 368 tests := []struct { 369 pod *v1.Pod 370 pods []*v1.Pod 371 nodes []*v1.Node 372 expectedScores framework.NodeScoreList 373 name string 374 }{ 375 { 376 377 // resources["intel.com/foo"] = 3 378 // resources["intel.com/bar"] = 5 379 // Node1 scores (used resources) on 0-10 scale 380 // Node1 Score: 381 // intel.com/foo: 382 // rawScoringFunction(used + requested / available) 383 // resourceScoringFunction((0+0),8) 384 // = 0/8 * 100 = 0 = rawScoringFunction(0) 385 // intel.com/bar: 386 // rawScoringFunction(used + requested / available) 387 // resourceScoringFunction((0+0),4) 388 // = 0/4 * 100 = 0 = rawScoringFunction(0) 389 // Node1 Score: (0 * 3) + (0 * 5) / 8 = 0 390 391 // Node2 scores (used resources) on 0-10 scale 392 // rawScoringFunction(used + requested / available) 393 // intel.com/foo: 394 // rawScoringFunction(used + requested / available) 395 // resourceScoringFunction((0+0),4) 396 // = 0/4 * 100 = 0 = rawScoringFunction(0) 397 // intel.com/bar: 398 // rawScoringFunction(used + requested / available) 399 // resourceScoringFunction((0+0),8) 400 // = 0/8 * 100 = 0 = rawScoringFunction(0) 401 // Node2 Score: (0 * 3) + (0 * 5) / 8 = 0 402 403 pod: st.MakePod().Obj(), 404 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResources2), makeNode("node2", 4000, 10000*1024*1024, extendedResources1)}, 405 expectedScores: []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: 0}}, 406 name: "nothing scheduled, nothing requested", 407 }, 408 { 409 410 // resources["intel.com/foo"] = 3 411 // resources["intel.com/bar"] = 5 412 // Node1 scores (used resources) on 0-10 scale 413 // Node1 Score: 414 // intel.com/foo: 415 // rawScoringFunction(used + requested / available) 416 // resourceScoringFunction((0+2),8) 417 // = 2/8 * 100 = 25 = rawScoringFunction(25) 418 // intel.com/bar: 419 // rawScoringFunction(used + requested / available) 420 // resourceScoringFunction((0+2),4) 421 // = 2/4 * 100 = 50 = rawScoringFunction(50) 422 // Node1 Score: (2 * 3) + (5 * 5) / 8 = 4 423 424 // Node2 scores (used resources) on 0-10 scale 425 // rawScoringFunction(used + requested / available) 426 // intel.com/foo: 427 // rawScoringFunction(used + requested / available) 428 // resourceScoringFunction((0+2),4) 429 // = 2/4 * 100 = 50 = rawScoringFunction(50) 430 // intel.com/bar: 431 // rawScoringFunction(used + requested / available) 432 // resourceScoringFunction((0+2),8) 433 // = 2/8 * 100 = 25 = rawScoringFunction(25) 434 // Node2 Score: (5 * 3) + (2 * 5) / 8 = 3 435 436 pod: st.MakePod().Req(extendedResourcePod1).Obj(), 437 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResources2), makeNode("node2", 4000, 10000*1024*1024, extendedResources1)}, 438 expectedScores: []framework.NodeScore{{Name: "node1", Score: 4}, {Name: "node2", Score: 3}}, 439 name: "resources requested, pods scheduled with less resources", 440 pods: []*v1.Pod{ 441 st.MakePod().Obj(), 442 }, 443 }, 444 { 445 446 // resources["intel.com/foo"] = 3 447 // resources["intel.com/bar"] = 5 448 // Node1 scores (used resources) on 0-10 scale 449 // Node1 Score: 450 // intel.com/foo: 451 // rawScoringFunction(used + requested / available) 452 // resourceScoringFunction((0+2),8) 453 // = 2/8 * 100 = 25 = rawScoringFunction(25) 454 // intel.com/bar: 455 // rawScoringFunction(used + requested / available) 456 // resourceScoringFunction((0+2),4) 457 // = 2/4 * 100 = 50 = rawScoringFunction(50) 458 // Node1 Score: (2 * 3) + (5 * 5) / 8 = 4 459 // Node2 scores (used resources) on 0-10 scale 460 // rawScoringFunction(used + requested / available) 461 // intel.com/foo: 462 // rawScoringFunction(used + requested / available) 463 // resourceScoringFunction((2+2),4) 464 // = 4/4 * 100 = 100 = rawScoringFunction(100) 465 // intel.com/bar: 466 // rawScoringFunction(used + requested / available) 467 // resourceScoringFunction((2+2),8) 468 // = 4/8 *100 = 50 = rawScoringFunction(50) 469 // Node2 Score: (10 * 3) + (5 * 5) / 8 = 7 470 471 pod: st.MakePod().Req(extendedResourcePod1).Obj(), 472 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResources2), makeNode("node2", 4000, 10000*1024*1024, extendedResources1)}, 473 expectedScores: []framework.NodeScore{{Name: "node1", Score: 4}, {Name: "node2", Score: 7}}, 474 name: "resources requested, pods scheduled with resources, on node with existing pod running ", 475 pods: []*v1.Pod{st.MakePod().Req(extendedResourcePod2).Node("node2").Obj()}, 476 }, 477 { 478 479 // resources["intel.com/foo"] = 3 480 // resources["intel.com/bar"] = 5 481 // Node1 scores (used resources) on 0-10 scale 482 // used + requested / available 483 // intel.com/foo Score: { (0 + 4) / 8 } * 10 = 0 484 // intel.com/bar Score: { (0 + 2) / 4 } * 10 = 0 485 // Node1 Score: (0.25 * 3) + (0.5 * 5) / 8 = 5 486 // resources["intel.com/foo"] = 3 487 // resources["intel.com/bar"] = 5 488 // Node2 scores (used resources) on 0-10 scale 489 // used + requested / available 490 // intel.com/foo Score: { (0 + 4) / 4 } * 10 = 0 491 // intel.com/bar Score: { (0 + 2) / 8 } * 10 = 0 492 // Node2 Score: (1 * 3) + (0.25 * 5) / 8 = 5 493 494 // resources["intel.com/foo"] = 3 495 // resources["intel.com/bar"] = 5 496 // Node1 scores (used resources) on 0-10 scale 497 // Node1 Score: 498 // intel.com/foo: 499 // rawScoringFunction(used + requested / available) 500 // resourceScoringFunction((0+4),8) 501 // 4/8 * 100 = 50 = rawScoringFunction(50) 502 // intel.com/bar: 503 // rawScoringFunction(used + requested / available) 504 // resourceScoringFunction((0+2),4) 505 // = 2/4 * 100 = 50 = rawScoringFunction(50) 506 // Node1 Score: (5 * 3) + (5 * 5) / 8 = 5 507 // Node2 scores (used resources) on 0-10 scale 508 // rawScoringFunction(used + requested / available) 509 // intel.com/foo: 510 // rawScoringFunction(used + requested / available) 511 // resourceScoringFunction((0+4),4) 512 // = 4/4 * 100 = 100 = rawScoringFunction(100) 513 // intel.com/bar: 514 // rawScoringFunction(used + requested / available) 515 // resourceScoringFunction((0+2),8) 516 // = 2/8 * 100 = 25 = rawScoringFunction(25) 517 // Node2 Score: (10 * 3) + (2 * 5) / 8 = 5 518 519 pod: st.MakePod().Req(extendedResourcePod2).Obj(), 520 nodes: []*v1.Node{makeNode("node1", 4000, 10000*1024*1024, extendedResources2), makeNode("node2", 4000, 10000*1024*1024, extendedResources1)}, 521 expectedScores: []framework.NodeScore{{Name: "node1", Score: 5}, {Name: "node2", Score: 5}}, 522 name: "resources requested, pods scheduled with more resources", 523 pods: []*v1.Pod{ 524 st.MakePod().Obj(), 525 }, 526 }, 527 } 528 529 for _, test := range tests { 530 t.Run(test.name, func(t *testing.T) { 531 state := framework.NewCycleState() 532 snapshot := cache.NewSnapshot(test.pods, test.nodes) 533 _, ctx := ktesting.NewTestContext(t) 534 fh, _ := runtime.NewFramework(ctx, nil, nil, runtime.WithSnapshotSharedLister(snapshot)) 535 536 args := config.NodeResourcesFitArgs{ 537 ScoringStrategy: &config.ScoringStrategy{ 538 Type: config.RequestedToCapacityRatio, 539 Resources: []config.ResourceSpec{ 540 {Name: "intel.com/foo", Weight: 3}, 541 {Name: "intel.com/bar", Weight: 5}, 542 }, 543 RequestedToCapacityRatio: &config.RequestedToCapacityRatioParam{ 544 Shape: []config.UtilizationShapePoint{ 545 {Utilization: 0, Score: 0}, 546 {Utilization: 100, Score: 1}, 547 }, 548 }, 549 }, 550 } 551 552 p, err := NewFit(ctx, &args, fh, plfeature.Features{}) 553 if err != nil { 554 t.Fatalf("unexpected error: %v", err) 555 } 556 557 status := p.(framework.PreScorePlugin).PreScore(context.Background(), state, test.pod, tf.BuildNodeInfos(test.nodes)) 558 if !status.IsSuccess() { 559 t.Errorf("PreScore is expected to return success, but didn't. Got status: %v", status) 560 } 561 562 var gotScores framework.NodeScoreList 563 for _, n := range test.nodes { 564 score, status := p.(framework.ScorePlugin).Score(context.Background(), state, test.pod, n.Name) 565 if !status.IsSuccess() { 566 t.Errorf("Score is expected to return success, but didn't. Got status: %v", status) 567 } 568 gotScores = append(gotScores, framework.NodeScore{Name: n.Name, Score: score}) 569 } 570 571 if diff := cmp.Diff(test.expectedScores, gotScores); diff != "" { 572 t.Errorf("Unexpected nodescore list (-want,+got):\n%s", diff) 573 } 574 }) 575 } 576 }