k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/scheduler/framework/plugins/noderesources/least_allocated_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 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 v1 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/util/validation/field" 26 "k8s.io/klog/v2/ktesting" 27 "k8s.io/kubernetes/pkg/scheduler/apis/config" 28 "k8s.io/kubernetes/pkg/scheduler/framework" 29 plfeature "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" 30 "k8s.io/kubernetes/pkg/scheduler/framework/runtime" 31 "k8s.io/kubernetes/pkg/scheduler/internal/cache" 32 st "k8s.io/kubernetes/pkg/scheduler/testing" 33 tf "k8s.io/kubernetes/pkg/scheduler/testing/framework" 34 ) 35 36 func TestLeastAllocatedScoringStrategy(t *testing.T) { 37 tests := []struct { 38 name string 39 requestedPod *v1.Pod 40 nodes []*v1.Node 41 existingPods []*v1.Pod 42 expectedScores framework.NodeScoreList 43 resources []config.ResourceSpec 44 wantErrs field.ErrorList 45 wantStatusCode framework.Code 46 }{ 47 { 48 // Node1 scores (remaining resources) on 0-MaxNodeScore scale 49 // CPU Score: ((4000 - 0) * MaxNodeScore) / 4000 = MaxNodeScore 50 // Memory Score: ((10000 - 0) * MaxNodeScore) / 10000 = MaxNodeScore 51 // Node1 Score: (100 + 100) / 2 = 100 52 // Node2 scores (remaining resources) on 0-MaxNodeScore scale 53 // CPU Score: ((4000 - 0) * MaxNodeScore) / 4000 = MaxNodeScore 54 // Memory Score: ((10000 - 0) * MaxNodeScore) / 10000 = MaxNodeScore 55 // Node2 Score: (MaxNodeScore + MaxNodeScore) / 2 = MaxNodeScore 56 name: "nothing scheduled, nothing requested", 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: nil, 63 expectedScores: []framework.NodeScore{{Name: "node1", Score: framework.MaxNodeScore}, {Name: "node2", Score: framework.MaxNodeScore}}, 64 resources: defaultResources, 65 }, 66 { 67 // Node1 scores on 0-MaxNodeScore scale 68 // CPU Score: ((4000 - 3000) * MaxNodeScore) / 4000 = 25 69 // Memory Score: ((10000 - 5000) * MaxNodeScore) / 10000 = 50 70 // Node1 Score: (25 + 50) / 2 = 37 71 // Node2 scores on 0-MaxNodeScore scale 72 // CPU Score: ((6000 - 3000) * MaxNodeScore) / 6000 = 50 73 // Memory Score: ((10000 - 5000) * MaxNodeScore) / 10000 = 50 74 // Node2 Score: (50 + 50) / 2 = 50 75 name: "nothing scheduled, resources requested, differently sized nodes", 76 requestedPod: st.MakePod(). 77 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 78 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 79 Obj(), 80 nodes: []*v1.Node{ 81 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 82 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 83 }, 84 existingPods: nil, 85 expectedScores: []framework.NodeScore{{Name: "node1", Score: 37}, {Name: "node2", Score: 50}}, 86 resources: defaultResources, 87 }, 88 { 89 name: "Resources not set, pods scheduled with error", 90 requestedPod: st.MakePod(). 91 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 92 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 93 Obj(), 94 nodes: []*v1.Node{ 95 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 96 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 97 }, 98 existingPods: nil, 99 expectedScores: []framework.NodeScore{{Name: "node1", Score: framework.MinNodeScore}, {Name: "node2", Score: framework.MinNodeScore}}, 100 resources: nil, 101 wantStatusCode: framework.Error, 102 }, 103 { 104 // Node1 scores on 0-MaxNodeScore scale 105 // CPU Score: ((4000 - 0) * MaxNodeScore) / 4000 = MaxNodeScore 106 // Memory Score: ((10000 - 0) * MaxNodeScore) / 10000 = MaxNodeScore 107 // Node1 Score: (MaxNodeScore + MaxNodeScore) / 2 = MaxNodeScore 108 // Node2 scores on 0-MaxNodeScore scale 109 // CPU Score: ((4000 - 0) * MaxNodeScore) / 4000 = MaxNodeScore 110 // Memory Score: ((10000 - 0) * MaxNodeScore) / 10000 = MaxNodeScore 111 // Node2 Score: (MaxNodeScore + MaxNodeScore) / 2 = MaxNodeScore 112 name: "no resources requested, pods scheduled", 113 requestedPod: st.MakePod().Obj(), 114 nodes: []*v1.Node{ 115 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 116 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 117 }, 118 existingPods: []*v1.Pod{ 119 st.MakePod().Node("node1").Obj(), 120 st.MakePod().Node("node1").Obj(), 121 st.MakePod().Node("node2").Obj(), 122 st.MakePod().Node("node2").Obj(), 123 }, 124 expectedScores: []framework.NodeScore{{Name: "node1", Score: framework.MaxNodeScore}, {Name: "node2", Score: framework.MaxNodeScore}}, 125 resources: defaultResources, 126 }, 127 { 128 // Node1 scores on 0-MaxNodeScore scale 129 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 130 // Memory Score: ((20000 - 0) * MaxNodeScore) / 20000 = MaxNodeScore 131 // Node1 Score: (40 + 100) / 2 = 70 132 // Node2 scores on 0-MaxNodeScore scale 133 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 134 // Memory Score: ((20000 - 5000) * MaxNodeScore) / 20000 = 75 135 // Node2 Score: (40 + 75) / 2 = 57 136 name: "no resources requested, pods scheduled with resources", 137 requestedPod: st.MakePod().Obj(), 138 nodes: []*v1.Node{ 139 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "20000"}).Obj(), 140 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "20000"}).Obj(), 141 }, 142 existingPods: []*v1.Pod{ 143 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 144 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 145 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 146 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 147 }, 148 expectedScores: []framework.NodeScore{{Name: "node1", Score: 70}, {Name: "node2", Score: 57}}, 149 resources: defaultResources, 150 }, 151 { 152 // Node1 scores on 0-MaxNodeScore scale 153 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 154 // Memory Score: ((20000 - 5000) * MaxNodeScore) / 20000 = 75 155 // Node1 Score: (40 + 75) / 2 = 57 156 // Node2 scores on 0-MaxNodeScore scale 157 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 158 // Memory Score: ((20000 - 10000) * MaxNodeScore) / 20000 = 50 159 // Node2 Score: (40 + 50) / 2 = 45 160 name: "resources requested, pods scheduled with resources", 161 requestedPod: st.MakePod(). 162 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 163 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 164 Obj(), 165 nodes: []*v1.Node{ 166 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "20000"}).Obj(), 167 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "20000"}).Obj(), 168 }, 169 existingPods: []*v1.Pod{ 170 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 171 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 172 }, 173 expectedScores: []framework.NodeScore{{Name: "node1", Score: 57}, {Name: "node2", Score: 45}}, 174 resources: defaultResources, 175 }, 176 { 177 // Node1 scores on 0-MaxNodeScore scale 178 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 179 // Memory Score: ((20000 - 5000) * MaxNodeScore) / 20000 = 75 180 // Node1 Score: (40 + 75) / 2 = 57 181 // Node2 scores on 0-MaxNodeScore scale 182 // CPU Score: ((10000 - 6000) * MaxNodeScore) / 10000 = 40 183 // Memory Score: ((50000 - 10000) * MaxNodeScore) / 50000 = 80 184 // Node2 Score: (40 + 80) / 2 = 60 185 name: "resources requested, pods scheduled with resources, differently sized nodes", 186 requestedPod: st.MakePod(). 187 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 188 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 189 Obj(), 190 nodes: []*v1.Node{ 191 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "20000"}).Obj(), 192 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "10000", "memory": "50000"}).Obj(), 193 }, 194 existingPods: []*v1.Pod{ 195 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 196 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 197 }, 198 expectedScores: []framework.NodeScore{{Name: "node1", Score: 57}, {Name: "node2", Score: 60}}, 199 resources: defaultResources, 200 }, 201 { 202 // Node1 scores on 0-MaxNodeScore scale 203 // CPU Score: ((4000 - 6000) * MaxNodeScore) / 4000 = 0 204 // Memory Score: ((10000 - 0) * MaxNodeScore) / 10000 = MaxNodeScore 205 // Node1 Score: (0 + MaxNodeScore) / 2 = 50 206 // Node2 scores on 0-MaxNodeScore scale 207 // CPU Score: ((4000 - 6000) * MaxNodeScore) / 4000 = 0 208 // Memory Score: ((10000 - 5000) * MaxNodeScore) / 10000 = 50 209 // Node2 Score: (0 + 50) / 2 = 25 210 name: "requested resources exceed node capacity", 211 requestedPod: st.MakePod().Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 212 nodes: []*v1.Node{ 213 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 214 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 215 }, 216 existingPods: []*v1.Pod{ 217 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 218 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 219 }, 220 expectedScores: []framework.NodeScore{{Name: "node1", Score: 50}, {Name: "node2", Score: 25}}, 221 resources: defaultResources, 222 }, 223 { 224 name: "zero node resources, pods scheduled with resources", 225 requestedPod: st.MakePod().Obj(), 226 nodes: []*v1.Node{ 227 st.MakeNode().Name("node1").Obj(), 228 st.MakeNode().Name("node2").Obj(), 229 }, 230 existingPods: []*v1.Pod{ 231 st.MakePod().Node("node1").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "0"}).Obj(), 232 st.MakePod().Node("node2").Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000"}).Obj(), 233 }, 234 expectedScores: []framework.NodeScore{{Name: "node1", Score: framework.MinNodeScore}, {Name: "node2", Score: framework.MinNodeScore}}, 235 resources: defaultResources, 236 }, 237 { 238 // CPU Score: ((4000 - 3000) *100) / 4000 = 25 239 // Memory Score: ((10000 - 5000) *100) / 10000 = 50 240 // Node1 Score: (25 * 1 + 50 * 2) / (1 + 2) = 41 241 // CPU Score: ((6000 - 3000) *100) / 6000 = 50 242 // Memory Score: ((10000 - 5000) *100) / 10000 = 50 243 // Node2 Score: (50 * 1 + 50 * 2) / (1 + 2) = 50 244 name: "nothing scheduled, resources requested with different weight on CPU and memory, differently sized nodes", 245 requestedPod: st.MakePod().Node("node1"). 246 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 247 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 248 Obj(), 249 nodes: []*v1.Node{ 250 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 251 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 252 }, 253 existingPods: nil, 254 expectedScores: []framework.NodeScore{{Name: "node1", Score: 41}, {Name: "node2", Score: 50}}, 255 resources: []config.ResourceSpec{ 256 {Name: "memory", Weight: 2}, 257 {Name: "cpu", Weight: 1}, 258 }, 259 }, 260 { 261 // resource with negative weight is not allowed 262 name: "resource with negative weight", 263 requestedPod: st.MakePod().Node("node1"). 264 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 265 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 266 Obj(), 267 nodes: []*v1.Node{ 268 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 269 }, 270 resources: []config.ResourceSpec{ 271 {Name: "memory", Weight: -1}, 272 {Name: "cpu", Weight: 1}, 273 }, 274 wantErrs: field.ErrorList{ 275 &field.Error{ 276 Type: field.ErrorTypeInvalid, 277 Field: "scoringStrategy.resources[0].weight", 278 }, 279 }, 280 }, 281 { 282 // resource with zero weight is not allowed 283 name: "resource with zero weight", 284 requestedPod: st.MakePod().Node("node1"). 285 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 286 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 287 Obj(), 288 nodes: []*v1.Node{ 289 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 290 }, 291 existingPods: nil, 292 expectedScores: []framework.NodeScore{{Name: "node1", Score: 41}, {Name: "node2", Score: 50}}, 293 resources: []config.ResourceSpec{ 294 {Name: "memory", Weight: 1}, 295 {Name: "cpu", Weight: 0}, 296 }, 297 wantErrs: field.ErrorList{ 298 &field.Error{ 299 Type: field.ErrorTypeInvalid, 300 Field: "scoringStrategy.resources[1].weight", 301 }, 302 }, 303 }, 304 { 305 // resource weight should be less than MaxNodeScore 306 name: "resource weight larger than MaxNodeScore", 307 requestedPod: st.MakePod().Node("node1"). 308 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 309 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 310 Obj(), 311 nodes: []*v1.Node{ 312 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "4000", "memory": "10000"}).Obj(), 313 }, 314 resources: []config.ResourceSpec{ 315 {Name: "memory", Weight: 1}, 316 {Name: "cpu", Weight: 101}, 317 }, 318 wantErrs: field.ErrorList{ 319 &field.Error{ 320 Type: field.ErrorTypeInvalid, 321 Field: "scoringStrategy.resources[1].weight", 322 }, 323 }, 324 }, 325 { 326 // Bypass extended resource if the pod does not request. 327 // For both nodes: cpuScore and memScore are 50 328 // Given that extended resource score are intentionally bypassed, 329 // the final scores are: 330 // - node1: (50 + 50) / 2 = 50 331 // - node2: (50 + 50) / 2 = 50 332 name: "bypass extended resource if the pod does not request", 333 requestedPod: st.MakePod().Node("node1"). 334 Req(map[v1.ResourceName]string{"cpu": "1000", "memory": "2000"}). 335 Req(map[v1.ResourceName]string{"cpu": "2000", "memory": "3000"}). 336 Obj(), 337 nodes: []*v1.Node{ 338 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 339 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000", v1.ResourceName(extendedRes): "4"}).Obj(), 340 }, 341 expectedScores: []framework.NodeScore{{Name: "node1", Score: 50}, {Name: "node2", Score: 50}}, 342 resources: extendedResourceSet, 343 }, 344 { 345 // Honor extended resource if the pod requests. 346 // For both nodes: cpuScore and memScore are 50. 347 // In terms of extended resource score: 348 // - node1 get: 2 / 4 * 100 = 50 349 // - node2 get: (10 - 2) / 10 * 100 = 80 350 // So the final scores are: 351 // - node1: (50 + 50 + 50) / 3 = 50 352 // - node2: (50 + 50 + 80) / 3 = 60 353 name: "honor extended resource if the pod requests", 354 requestedPod: st.MakePod().Node("node1"). 355 Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "5000", v1.ResourceName(extendedRes): "2"}). 356 Obj(), 357 nodes: []*v1.Node{ 358 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000", v1.ResourceName(extendedRes): "4"}).Obj(), 359 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000", v1.ResourceName(extendedRes): "10"}).Obj(), 360 }, 361 existingPods: nil, 362 expectedScores: []framework.NodeScore{{Name: "node1", Score: 50}, {Name: "node2", Score: 60}}, 363 resources: extendedResourceSet, 364 }, 365 { 366 // If the node doesn't have a resource 367 // CPU Score: ((6000 - 3000) * 100) / 6000 = 50 368 // Memory Score: ((10000 - 4000) * 100) / 10000 = 60 369 // Node1 Score: (50 * 1 + 60 * 1) / (1 + 1) = 55 370 // Node2 Score: (50 * 1 + 60 * 1) / (1 + 1) = 55 371 name: "if the node doesn't have a resource", 372 requestedPod: st.MakePod().Node("node1"). 373 Req(map[v1.ResourceName]string{"cpu": "3000", "memory": "4000"}). 374 Obj(), 375 nodes: []*v1.Node{ 376 st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000"}).Obj(), 377 st.MakeNode().Name("node2").Capacity(map[v1.ResourceName]string{"cpu": "6000", "memory": "10000", v1.ResourceName(extendedRes): "4"}).Obj(), 378 }, 379 expectedScores: []framework.NodeScore{{Name: "node1", Score: 55}, {Name: "node2", Score: 55}}, 380 resources: []config.ResourceSpec{ 381 {Name: extendedRes, Weight: 2}, 382 {Name: string(v1.ResourceCPU), Weight: 1}, 383 {Name: string(v1.ResourceMemory), Weight: 1}, 384 }, 385 }, 386 } 387 388 for _, test := range tests { 389 t.Run(test.name, func(t *testing.T) { 390 _, ctx := ktesting.NewTestContext(t) 391 ctx, cancel := context.WithCancel(ctx) 392 defer cancel() 393 394 state := framework.NewCycleState() 395 snapshot := cache.NewSnapshot(test.existingPods, test.nodes) 396 fh, _ := runtime.NewFramework(ctx, nil, nil, runtime.WithSnapshotSharedLister(snapshot)) 397 398 p, err := NewFit( 399 ctx, 400 &config.NodeResourcesFitArgs{ 401 ScoringStrategy: &config.ScoringStrategy{ 402 Type: config.LeastAllocated, 403 Resources: test.resources, 404 }, 405 }, fh, plfeature.Features{}) 406 407 if diff := cmp.Diff(test.wantErrs.ToAggregate(), err, ignoreBadValueDetail); diff != "" { 408 t.Fatalf("got err (-want,+got):\n%s", diff) 409 } 410 if err != nil { 411 return 412 } 413 414 status := p.(framework.PreScorePlugin).PreScore(ctx, state, test.requestedPod, tf.BuildNodeInfos(test.nodes)) 415 if !status.IsSuccess() { 416 t.Errorf("PreScore is expected to return success, but didn't. Got status: %v", status) 417 } 418 419 var gotScores framework.NodeScoreList 420 for _, n := range test.nodes { 421 score, status := p.(framework.ScorePlugin).Score(ctx, state, test.requestedPod, n.Name) 422 if status.Code() != test.wantStatusCode { 423 t.Errorf("unexpected status code, want: %v, got: %v", test.wantStatusCode, status.Code()) 424 } 425 gotScores = append(gotScores, framework.NodeScore{Name: n.Name, Score: score}) 426 } 427 428 if diff := cmp.Diff(test.expectedScores, gotScores); diff != "" { 429 t.Errorf("Unexpected scores (-want,+got):\n%s", diff) 430 } 431 }) 432 } 433 }