k8s.io/kubernetes@v1.29.3/pkg/kubelet/apis/podresources/server_v1_test.go (about) 1 /* 2 Copyright 2018 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 podresources 18 19 import ( 20 "context" 21 "fmt" 22 "reflect" 23 "sort" 24 "testing" 25 26 "github.com/golang/mock/gomock" 27 v1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/types" 30 utilfeature "k8s.io/apiserver/pkg/util/feature" 31 featuregatetesting "k8s.io/component-base/featuregate/testing" 32 podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1" 33 pkgfeatures "k8s.io/kubernetes/pkg/features" 34 podresourcetest "k8s.io/kubernetes/pkg/kubelet/apis/podresources/testing" 35 ) 36 37 func TestListPodResourcesV1(t *testing.T) { 38 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)() 39 40 podName := "pod-name" 41 podNamespace := "pod-namespace" 42 podUID := types.UID("pod-uid") 43 containerName := "container-name" 44 numaID := int64(1) 45 46 mockCtrl := gomock.NewController(t) 47 defer mockCtrl.Finish() 48 49 devs := []*podresourcesapi.ContainerDevices{ 50 { 51 ResourceName: "resource", 52 DeviceIds: []string{"dev0", "dev1"}, 53 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 54 }, 55 } 56 57 cpus := []int64{12, 23, 30} 58 59 memory := []*podresourcesapi.ContainerMemory{ 60 { 61 MemoryType: "memory", 62 Size_: 1073741824, 63 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 64 }, 65 { 66 MemoryType: "hugepages-1Gi", 67 Size_: 1073741824, 68 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 69 }, 70 } 71 72 containers := []v1.Container{ 73 { 74 Name: containerName, 75 }, 76 } 77 pods := []*v1.Pod{ 78 { 79 ObjectMeta: metav1.ObjectMeta{ 80 Name: podName, 81 Namespace: podNamespace, 82 UID: podUID, 83 }, 84 Spec: v1.PodSpec{ 85 Containers: containers, 86 }, 87 }, 88 } 89 90 pluginCDIDevices := []*podresourcesapi.CDIDevice{{Name: "dra-dev0"}, {Name: "dra-dev1"}} 91 draDevs := []*podresourcesapi.DynamicResource{ 92 { 93 ClassName: "resource-class", 94 ClaimName: "claim-name", 95 ClaimNamespace: "default", 96 ClaimResources: []*podresourcesapi.ClaimResource{{CDIDevices: pluginCDIDevices}}, 97 }, 98 } 99 100 for _, tc := range []struct { 101 desc string 102 pods []*v1.Pod 103 devices []*podresourcesapi.ContainerDevices 104 cpus []int64 105 memory []*podresourcesapi.ContainerMemory 106 dynamicResources []*podresourcesapi.DynamicResource 107 expectedResponse *podresourcesapi.ListPodResourcesResponse 108 }{ 109 { 110 desc: "no pods", 111 pods: []*v1.Pod{}, 112 devices: []*podresourcesapi.ContainerDevices{}, 113 cpus: []int64{}, 114 memory: []*podresourcesapi.ContainerMemory{}, 115 dynamicResources: []*podresourcesapi.DynamicResource{}, 116 expectedResponse: &podresourcesapi.ListPodResourcesResponse{}, 117 }, 118 { 119 desc: "pod without devices", 120 pods: pods, 121 devices: []*podresourcesapi.ContainerDevices{}, 122 cpus: []int64{}, 123 memory: []*podresourcesapi.ContainerMemory{}, 124 dynamicResources: []*podresourcesapi.DynamicResource{}, 125 expectedResponse: &podresourcesapi.ListPodResourcesResponse{ 126 PodResources: []*podresourcesapi.PodResources{ 127 { 128 Name: podName, 129 Namespace: podNamespace, 130 Containers: []*podresourcesapi.ContainerResources{ 131 { 132 Name: containerName, 133 Devices: []*podresourcesapi.ContainerDevices{}, 134 DynamicResources: []*podresourcesapi.DynamicResource{}, 135 }, 136 }, 137 }, 138 }, 139 }, 140 }, 141 { 142 desc: "pod with devices", 143 pods: pods, 144 devices: devs, 145 cpus: cpus, 146 memory: memory, 147 dynamicResources: []*podresourcesapi.DynamicResource{}, 148 expectedResponse: &podresourcesapi.ListPodResourcesResponse{ 149 PodResources: []*podresourcesapi.PodResources{ 150 { 151 Name: podName, 152 Namespace: podNamespace, 153 Containers: []*podresourcesapi.ContainerResources{ 154 { 155 Name: containerName, 156 Devices: devs, 157 CpuIds: cpus, 158 Memory: memory, 159 DynamicResources: []*podresourcesapi.DynamicResource{}, 160 }, 161 }, 162 }, 163 }, 164 }, 165 }, 166 { 167 desc: "pod with dynamic resources", 168 pods: pods, 169 devices: []*podresourcesapi.ContainerDevices{}, 170 cpus: cpus, 171 memory: memory, 172 dynamicResources: draDevs, 173 expectedResponse: &podresourcesapi.ListPodResourcesResponse{ 174 PodResources: []*podresourcesapi.PodResources{ 175 { 176 Name: podName, 177 Namespace: podNamespace, 178 Containers: []*podresourcesapi.ContainerResources{ 179 { 180 Name: containerName, 181 Devices: []*podresourcesapi.ContainerDevices{}, 182 CpuIds: cpus, 183 Memory: memory, 184 DynamicResources: draDevs, 185 }, 186 }, 187 }, 188 }, 189 }, 190 }, 191 { 192 desc: "pod with dynamic resources and devices", 193 pods: pods, 194 devices: devs, 195 cpus: cpus, 196 memory: memory, 197 dynamicResources: draDevs, 198 expectedResponse: &podresourcesapi.ListPodResourcesResponse{ 199 PodResources: []*podresourcesapi.PodResources{ 200 { 201 Name: podName, 202 Namespace: podNamespace, 203 Containers: []*podresourcesapi.ContainerResources{ 204 { 205 Name: containerName, 206 Devices: devs, 207 CpuIds: cpus, 208 Memory: memory, 209 DynamicResources: draDevs, 210 }, 211 }, 212 }, 213 }, 214 }, 215 }, 216 } { 217 t.Run(tc.desc, func(t *testing.T) { 218 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl) 219 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl) 220 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl) 221 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl) 222 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl) 223 224 mockPodsProvider.EXPECT().GetPods().Return(tc.pods).AnyTimes().AnyTimes() 225 mockDevicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(tc.devices).AnyTimes() 226 mockCPUsProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(tc.cpus).AnyTimes() 227 mockMemoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(tc.memory).AnyTimes() 228 mockDynamicResourcesProvider.EXPECT().GetDynamicResources(pods[0], &containers[0]).Return(tc.dynamicResources).AnyTimes() 229 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes() 230 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return([]int64{}).AnyTimes() 231 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return([]*podresourcesapi.ContainerDevices{}).AnyTimes() 232 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return([]*podresourcesapi.ContainerMemory{}).AnyTimes() 233 234 providers := PodResourcesProviders{ 235 Pods: mockPodsProvider, 236 Devices: mockDevicesProvider, 237 Cpus: mockCPUsProvider, 238 Memory: mockMemoryProvider, 239 DynamicResources: mockDynamicResourcesProvider, 240 } 241 server := NewV1PodResourcesServer(providers) 242 resp, err := server.List(context.TODO(), &podresourcesapi.ListPodResourcesRequest{}) 243 if err != nil { 244 t.Errorf("want err = %v, got %q", nil, err) 245 } 246 if !equalListResponse(tc.expectedResponse, resp) { 247 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String()) 248 } 249 }) 250 } 251 } 252 253 func TestAllocatableResources(t *testing.T) { 254 mockCtrl := gomock.NewController(t) 255 defer mockCtrl.Finish() 256 257 allDevs := []*podresourcesapi.ContainerDevices{ 258 { 259 ResourceName: "resource", 260 DeviceIds: []string{"dev0"}, 261 Topology: &podresourcesapi.TopologyInfo{ 262 Nodes: []*podresourcesapi.NUMANode{ 263 { 264 ID: 0, 265 }, 266 }, 267 }, 268 }, 269 { 270 ResourceName: "resource", 271 DeviceIds: []string{"dev1"}, 272 Topology: &podresourcesapi.TopologyInfo{ 273 Nodes: []*podresourcesapi.NUMANode{ 274 { 275 ID: 1, 276 }, 277 }, 278 }, 279 }, 280 { 281 ResourceName: "resource-nt", 282 DeviceIds: []string{"devA"}, 283 }, 284 { 285 ResourceName: "resource-mm", 286 DeviceIds: []string{"devM0"}, 287 Topology: &podresourcesapi.TopologyInfo{ 288 Nodes: []*podresourcesapi.NUMANode{ 289 { 290 ID: 0, 291 }, 292 }, 293 }, 294 }, 295 { 296 ResourceName: "resource-mm", 297 DeviceIds: []string{"devMM"}, 298 Topology: &podresourcesapi.TopologyInfo{ 299 Nodes: []*podresourcesapi.NUMANode{ 300 { 301 ID: 0, 302 }, 303 { 304 ID: 1, 305 }, 306 }, 307 }, 308 }, 309 } 310 311 allCPUs := []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 312 313 allMemory := []*podresourcesapi.ContainerMemory{ 314 { 315 MemoryType: "memory", 316 Size_: 5368709120, 317 Topology: &podresourcesapi.TopologyInfo{ 318 Nodes: []*podresourcesapi.NUMANode{ 319 { 320 ID: 0, 321 }, 322 }, 323 }, 324 }, 325 { 326 MemoryType: "hugepages-2Mi", 327 Size_: 1073741824, 328 Topology: &podresourcesapi.TopologyInfo{ 329 Nodes: []*podresourcesapi.NUMANode{ 330 { 331 ID: 0, 332 }, 333 }, 334 }, 335 }, 336 { 337 MemoryType: "memory", 338 Size_: 5368709120, 339 Topology: &podresourcesapi.TopologyInfo{ 340 Nodes: []*podresourcesapi.NUMANode{ 341 { 342 ID: 1, 343 }, 344 }, 345 }, 346 }, 347 { 348 MemoryType: "hugepages-2Mi", 349 Size_: 1073741824, 350 Topology: &podresourcesapi.TopologyInfo{ 351 Nodes: []*podresourcesapi.NUMANode{ 352 { 353 ID: 1, 354 }, 355 }, 356 }, 357 }, 358 } 359 360 for _, tc := range []struct { 361 desc string 362 allCPUs []int64 363 allDevices []*podresourcesapi.ContainerDevices 364 allMemory []*podresourcesapi.ContainerMemory 365 expectedAllocatableResourcesResponse *podresourcesapi.AllocatableResourcesResponse 366 }{ 367 { 368 desc: "no devices, no CPUs", 369 allCPUs: []int64{}, 370 allDevices: []*podresourcesapi.ContainerDevices{}, 371 allMemory: []*podresourcesapi.ContainerMemory{}, 372 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{}, 373 }, 374 { 375 desc: "no devices, all CPUs", 376 allCPUs: allCPUs, 377 allDevices: []*podresourcesapi.ContainerDevices{}, 378 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{ 379 CpuIds: allCPUs, 380 }, 381 }, 382 { 383 desc: "no devices, no CPUs, all memory", 384 allCPUs: []int64{}, 385 allDevices: []*podresourcesapi.ContainerDevices{}, 386 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{ 387 Memory: allMemory, 388 }, 389 }, 390 { 391 desc: "with devices, all CPUs", 392 allCPUs: allCPUs, 393 allDevices: allDevs, 394 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{ 395 CpuIds: allCPUs, 396 Devices: []*podresourcesapi.ContainerDevices{ 397 { 398 ResourceName: "resource", 399 DeviceIds: []string{"dev0"}, 400 Topology: &podresourcesapi.TopologyInfo{ 401 Nodes: []*podresourcesapi.NUMANode{ 402 { 403 ID: 0, 404 }, 405 }, 406 }, 407 }, 408 { 409 ResourceName: "resource", 410 DeviceIds: []string{"dev1"}, 411 Topology: &podresourcesapi.TopologyInfo{ 412 Nodes: []*podresourcesapi.NUMANode{ 413 { 414 ID: 1, 415 }, 416 }, 417 }, 418 }, 419 { 420 ResourceName: "resource-nt", 421 DeviceIds: []string{"devA"}, 422 }, 423 { 424 ResourceName: "resource-mm", 425 DeviceIds: []string{"devM0"}, 426 Topology: &podresourcesapi.TopologyInfo{ 427 Nodes: []*podresourcesapi.NUMANode{ 428 { 429 ID: 0, 430 }, 431 }, 432 }, 433 }, 434 { 435 ResourceName: "resource-mm", 436 DeviceIds: []string{"devMM"}, 437 Topology: &podresourcesapi.TopologyInfo{ 438 Nodes: []*podresourcesapi.NUMANode{ 439 { 440 ID: 0, 441 }, 442 { 443 ID: 1, 444 }, 445 }, 446 }, 447 }, 448 }, 449 }, 450 }, 451 { 452 desc: "with devices, no CPUs", 453 allCPUs: []int64{}, 454 allDevices: allDevs, 455 expectedAllocatableResourcesResponse: &podresourcesapi.AllocatableResourcesResponse{ 456 Devices: []*podresourcesapi.ContainerDevices{ 457 { 458 ResourceName: "resource", 459 DeviceIds: []string{"dev0"}, 460 Topology: &podresourcesapi.TopologyInfo{ 461 Nodes: []*podresourcesapi.NUMANode{ 462 { 463 ID: 0, 464 }, 465 }, 466 }, 467 }, 468 { 469 ResourceName: "resource", 470 DeviceIds: []string{"dev1"}, 471 Topology: &podresourcesapi.TopologyInfo{ 472 Nodes: []*podresourcesapi.NUMANode{ 473 { 474 ID: 1, 475 }, 476 }, 477 }, 478 }, 479 { 480 ResourceName: "resource-nt", 481 DeviceIds: []string{"devA"}, 482 }, 483 { 484 ResourceName: "resource-mm", 485 DeviceIds: []string{"devM0"}, 486 Topology: &podresourcesapi.TopologyInfo{ 487 Nodes: []*podresourcesapi.NUMANode{ 488 { 489 ID: 0, 490 }, 491 }, 492 }, 493 }, 494 { 495 ResourceName: "resource-mm", 496 DeviceIds: []string{"devMM"}, 497 Topology: &podresourcesapi.TopologyInfo{ 498 Nodes: []*podresourcesapi.NUMANode{ 499 { 500 ID: 0, 501 }, 502 { 503 ID: 1, 504 }, 505 }, 506 }, 507 }, 508 }, 509 }, 510 }, 511 } { 512 t.Run(tc.desc, func(t *testing.T) { 513 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl) 514 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl) 515 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl) 516 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl) 517 518 mockDevicesProvider.EXPECT().GetDevices("", "").Return([]*podresourcesapi.ContainerDevices{}).AnyTimes() 519 mockCPUsProvider.EXPECT().GetCPUs("", "").Return([]int64{}).AnyTimes() 520 mockMemoryProvider.EXPECT().GetMemory("", "").Return([]*podresourcesapi.ContainerMemory{}).AnyTimes() 521 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes() 522 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return(tc.allDevices).AnyTimes() 523 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return(tc.allCPUs).AnyTimes() 524 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return(tc.allMemory).AnyTimes() 525 526 providers := PodResourcesProviders{ 527 Pods: mockPodsProvider, 528 Devices: mockDevicesProvider, 529 Cpus: mockCPUsProvider, 530 Memory: mockMemoryProvider, 531 } 532 server := NewV1PodResourcesServer(providers) 533 534 resp, err := server.GetAllocatableResources(context.TODO(), &podresourcesapi.AllocatableResourcesRequest{}) 535 if err != nil { 536 t.Errorf("want err = %v, got %q", nil, err) 537 } 538 539 if !equalAllocatableResourcesResponse(tc.expectedAllocatableResourcesResponse, resp) { 540 t.Errorf("want resp = %s, got %s", tc.expectedAllocatableResourcesResponse.String(), resp.String()) 541 } 542 }) 543 } 544 } 545 546 func TestGetPodResourcesV1(t *testing.T) { 547 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesGet, true)() 548 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.KubeletPodResourcesDynamicResources, true)() 549 550 podName := "pod-name" 551 podNamespace := "pod-namespace" 552 podUID := types.UID("pod-uid") 553 containerName := "container-name" 554 numaID := int64(1) 555 556 mockCtrl := gomock.NewController(t) 557 defer mockCtrl.Finish() 558 559 devs := []*podresourcesapi.ContainerDevices{ 560 { 561 ResourceName: "resource", 562 DeviceIds: []string{"dev0", "dev1"}, 563 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 564 }, 565 } 566 567 cpus := []int64{12, 23, 30} 568 569 memory := []*podresourcesapi.ContainerMemory{ 570 { 571 MemoryType: "memory", 572 Size_: 1073741824, 573 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 574 }, 575 { 576 MemoryType: "hugepages-1Gi", 577 Size_: 1073741824, 578 Topology: &podresourcesapi.TopologyInfo{Nodes: []*podresourcesapi.NUMANode{{ID: numaID}}}, 579 }, 580 } 581 582 containers := []v1.Container{ 583 { 584 Name: containerName, 585 }, 586 } 587 588 pod := &v1.Pod{ 589 ObjectMeta: metav1.ObjectMeta{ 590 Name: podName, 591 Namespace: podNamespace, 592 UID: podUID, 593 }, 594 Spec: v1.PodSpec{ 595 Containers: containers, 596 }, 597 } 598 599 pluginCDIDevices := []*podresourcesapi.CDIDevice{{Name: "dra-dev0"}, {Name: "dra-dev1"}} 600 draDevs := []*podresourcesapi.DynamicResource{ 601 { 602 ClassName: "resource-class", 603 ClaimName: "claim-name", 604 ClaimNamespace: "default", 605 ClaimResources: []*podresourcesapi.ClaimResource{{CDIDevices: pluginCDIDevices}}, 606 }, 607 } 608 609 for _, tc := range []struct { 610 desc string 611 err error 612 exist bool 613 pod *v1.Pod 614 devices []*podresourcesapi.ContainerDevices 615 cpus []int64 616 memory []*podresourcesapi.ContainerMemory 617 dynamicResources []*podresourcesapi.DynamicResource 618 expectedResponse *podresourcesapi.GetPodResourcesResponse 619 }{ 620 { 621 desc: "pod not exist", 622 err: fmt.Errorf("pod %s in namespace %s not found", podName, podNamespace), 623 exist: false, 624 pod: nil, 625 devices: []*podresourcesapi.ContainerDevices{}, 626 cpus: []int64{}, 627 memory: []*podresourcesapi.ContainerMemory{}, 628 dynamicResources: []*podresourcesapi.DynamicResource{}, 629 630 expectedResponse: &podresourcesapi.GetPodResourcesResponse{}, 631 }, 632 { 633 desc: "pod without devices", 634 err: nil, 635 exist: true, 636 pod: pod, 637 devices: []*podresourcesapi.ContainerDevices{}, 638 cpus: []int64{}, 639 memory: []*podresourcesapi.ContainerMemory{}, 640 dynamicResources: []*podresourcesapi.DynamicResource{}, 641 expectedResponse: &podresourcesapi.GetPodResourcesResponse{ 642 PodResources: &podresourcesapi.PodResources{ 643 Name: podName, 644 Namespace: podNamespace, 645 Containers: []*podresourcesapi.ContainerResources{ 646 { 647 Name: containerName, 648 Devices: []*podresourcesapi.ContainerDevices{}, 649 DynamicResources: []*podresourcesapi.DynamicResource{}, 650 }, 651 }, 652 }, 653 }, 654 }, 655 { 656 desc: "pod with devices", 657 err: nil, 658 exist: true, 659 pod: pod, 660 devices: devs, 661 cpus: cpus, 662 memory: memory, 663 dynamicResources: draDevs, 664 expectedResponse: &podresourcesapi.GetPodResourcesResponse{ 665 PodResources: &podresourcesapi.PodResources{ 666 Name: podName, 667 Namespace: podNamespace, 668 Containers: []*podresourcesapi.ContainerResources{ 669 { 670 Name: containerName, 671 Devices: devs, 672 CpuIds: cpus, 673 Memory: memory, 674 DynamicResources: draDevs, 675 }, 676 }, 677 }, 678 }, 679 }, 680 } { 681 t.Run(tc.desc, func(t *testing.T) { 682 mockDevicesProvider := podresourcetest.NewMockDevicesProvider(mockCtrl) 683 mockPodsProvider := podresourcetest.NewMockPodsProvider(mockCtrl) 684 mockCPUsProvider := podresourcetest.NewMockCPUsProvider(mockCtrl) 685 mockMemoryProvider := podresourcetest.NewMockMemoryProvider(mockCtrl) 686 mockDynamicResourcesProvider := podresourcetest.NewMockDynamicResourcesProvider(mockCtrl) 687 688 mockPodsProvider.EXPECT().GetPodByName(podNamespace, podName).Return(tc.pod, tc.exist).AnyTimes() 689 mockDevicesProvider.EXPECT().GetDevices(string(podUID), containerName).Return(tc.devices).AnyTimes() 690 mockCPUsProvider.EXPECT().GetCPUs(string(podUID), containerName).Return(tc.cpus).AnyTimes() 691 mockMemoryProvider.EXPECT().GetMemory(string(podUID), containerName).Return(tc.memory).AnyTimes() 692 mockDynamicResourcesProvider.EXPECT().GetDynamicResources(pod, &containers[0]).Return(tc.dynamicResources).AnyTimes() 693 mockDevicesProvider.EXPECT().UpdateAllocatedDevices().Return().AnyTimes() 694 mockCPUsProvider.EXPECT().GetAllocatableCPUs().Return([]int64{}).AnyTimes() 695 mockDevicesProvider.EXPECT().GetAllocatableDevices().Return([]*podresourcesapi.ContainerDevices{}).AnyTimes() 696 mockMemoryProvider.EXPECT().GetAllocatableMemory().Return([]*podresourcesapi.ContainerMemory{}).AnyTimes() 697 698 providers := PodResourcesProviders{ 699 Pods: mockPodsProvider, 700 Devices: mockDevicesProvider, 701 Cpus: mockCPUsProvider, 702 Memory: mockMemoryProvider, 703 DynamicResources: mockDynamicResourcesProvider, 704 } 705 server := NewV1PodResourcesServer(providers) 706 podReq := &podresourcesapi.GetPodResourcesRequest{PodName: podName, PodNamespace: podNamespace} 707 resp, err := server.Get(context.TODO(), podReq) 708 709 if err != nil { 710 if err.Error() != tc.err.Error() { 711 t.Errorf("want exit = %v, got %v", tc.err, err) 712 } 713 } else { 714 if err != tc.err { 715 t.Errorf("want exit = %v, got %v", tc.err, err) 716 } else { 717 if !equalGetResponse(tc.expectedResponse, resp) { 718 t.Errorf("want resp = %s, got %s", tc.expectedResponse.String(), resp.String()) 719 } 720 } 721 } 722 }) 723 } 724 725 } 726 727 func equalListResponse(respA, respB *podresourcesapi.ListPodResourcesResponse) bool { 728 if len(respA.PodResources) != len(respB.PodResources) { 729 return false 730 } 731 for idx := 0; idx < len(respA.PodResources); idx++ { 732 podResA := respA.PodResources[idx] 733 podResB := respB.PodResources[idx] 734 if podResA.Name != podResB.Name { 735 return false 736 } 737 if podResA.Namespace != podResB.Namespace { 738 return false 739 } 740 if len(podResA.Containers) != len(podResB.Containers) { 741 return false 742 } 743 for jdx := 0; jdx < len(podResA.Containers); jdx++ { 744 cntA := podResA.Containers[jdx] 745 cntB := podResB.Containers[jdx] 746 747 if cntA.Name != cntB.Name { 748 return false 749 } 750 if !equalInt64s(cntA.CpuIds, cntB.CpuIds) { 751 return false 752 } 753 754 if !equalContainerDevices(cntA.Devices, cntB.Devices) { 755 return false 756 } 757 758 if !equalDynamicResources(cntA.DynamicResources, cntB.DynamicResources) { 759 return false 760 } 761 } 762 } 763 return true 764 } 765 766 func equalDynamicResources(draResA, draResB []*podresourcesapi.DynamicResource) bool { 767 if len(draResA) != len(draResB) { 768 return false 769 } 770 771 for idx := 0; idx < len(draResA); idx++ { 772 cntDraResA := draResA[idx] 773 cntDraResB := draResB[idx] 774 775 if cntDraResA.ClassName != cntDraResB.ClassName { 776 return false 777 } 778 if cntDraResA.ClaimName != cntDraResB.ClaimName { 779 return false 780 } 781 if cntDraResA.ClaimNamespace != cntDraResB.ClaimNamespace { 782 return false 783 } 784 if len(cntDraResA.ClaimResources) != len(cntDraResB.ClaimResources) { 785 return false 786 } 787 for i := 0; i < len(cntDraResA.ClaimResources); i++ { 788 claimResA := cntDraResA.ClaimResources[i] 789 claimResB := cntDraResB.ClaimResources[i] 790 if len(claimResA.CDIDevices) != len(claimResB.CDIDevices) { 791 return false 792 } 793 for y := 0; y < len(claimResA.CDIDevices); y++ { 794 cdiDeviceA := claimResA.CDIDevices[y] 795 cdiDeviceB := claimResB.CDIDevices[y] 796 if cdiDeviceA.Name != cdiDeviceB.Name { 797 return false 798 } 799 } 800 } 801 } 802 803 return true 804 } 805 806 func equalContainerDevices(devA, devB []*podresourcesapi.ContainerDevices) bool { 807 if len(devA) != len(devB) { 808 return false 809 } 810 811 for idx := 0; idx < len(devA); idx++ { 812 cntDevA := devA[idx] 813 cntDevB := devB[idx] 814 815 if cntDevA.ResourceName != cntDevB.ResourceName { 816 return false 817 } 818 if !equalTopology(cntDevA.Topology, cntDevB.Topology) { 819 return false 820 } 821 if !equalStrings(cntDevA.DeviceIds, cntDevB.DeviceIds) { 822 return false 823 } 824 } 825 826 return true 827 } 828 829 func equalInt64s(a, b []int64) bool { 830 if len(a) != len(b) { 831 return false 832 } 833 aCopy := append([]int64{}, a...) 834 sort.Slice(aCopy, func(i, j int) bool { return aCopy[i] < aCopy[j] }) 835 bCopy := append([]int64{}, b...) 836 sort.Slice(bCopy, func(i, j int) bool { return bCopy[i] < bCopy[j] }) 837 return reflect.DeepEqual(aCopy, bCopy) 838 } 839 840 func equalStrings(a, b []string) bool { 841 if len(a) != len(b) { 842 return false 843 } 844 aCopy := append([]string{}, a...) 845 sort.Strings(aCopy) 846 bCopy := append([]string{}, b...) 847 sort.Strings(bCopy) 848 return reflect.DeepEqual(aCopy, bCopy) 849 } 850 851 func equalTopology(a, b *podresourcesapi.TopologyInfo) bool { 852 if a == nil && b != nil { 853 return false 854 } 855 if a != nil && b == nil { 856 return false 857 } 858 return reflect.DeepEqual(a, b) 859 } 860 861 func equalAllocatableResourcesResponse(respA, respB *podresourcesapi.AllocatableResourcesResponse) bool { 862 if !equalInt64s(respA.CpuIds, respB.CpuIds) { 863 return false 864 } 865 return equalContainerDevices(respA.Devices, respB.Devices) 866 } 867 868 func equalGetResponse(ResA, ResB *podresourcesapi.GetPodResourcesResponse) bool { 869 podResA := ResA.PodResources 870 podResB := ResB.PodResources 871 if podResA.Name != podResB.Name { 872 return false 873 } 874 if podResA.Namespace != podResB.Namespace { 875 return false 876 } 877 if len(podResA.Containers) != len(podResB.Containers) { 878 return false 879 } 880 for jdx := 0; jdx < len(podResA.Containers); jdx++ { 881 cntA := podResA.Containers[jdx] 882 cntB := podResB.Containers[jdx] 883 884 if cntA.Name != cntB.Name { 885 return false 886 } 887 if !equalInt64s(cntA.CpuIds, cntB.CpuIds) { 888 return false 889 } 890 891 if !equalContainerDevices(cntA.Devices, cntB.Devices) { 892 return false 893 } 894 895 if !equalDynamicResources(cntA.DynamicResources, cntB.DynamicResources) { 896 return false 897 } 898 899 } 900 return true 901 }