k8s.io/client-go@v0.31.1/discovery/aggregated_discovery_test.go (about) 1 /* 2 Copyright 2022 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 discovery 18 19 import ( 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 apidiscovery "k8s.io/api/apidiscovery/v2" 24 apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 ) 28 29 func TestSplitGroupsAndResources(t *testing.T) { 30 tests := []struct { 31 name string 32 agg apidiscovery.APIGroupDiscoveryList 33 expectedGroups metav1.APIGroupList 34 expectedGVResources map[schema.GroupVersion]*metav1.APIResourceList 35 expectedFailedGVs map[schema.GroupVersion]error 36 }{ 37 { 38 name: "Aggregated discovery: core/v1 group and pod resource", 39 agg: apidiscovery.APIGroupDiscoveryList{ 40 Items: []apidiscovery.APIGroupDiscovery{ 41 { 42 ObjectMeta: metav1.ObjectMeta{ 43 Name: "", 44 }, 45 Versions: []apidiscovery.APIVersionDiscovery{ 46 { 47 Version: "v1", 48 Resources: []apidiscovery.APIResourceDiscovery{ 49 { 50 Resource: "pods", 51 ResponseKind: &metav1.GroupVersionKind{ 52 Group: "", 53 Version: "v1", 54 Kind: "Pod", 55 }, 56 Scope: apidiscovery.ScopeNamespace, 57 }, 58 }, 59 }, 60 }, 61 }, 62 }, 63 }, 64 expectedGroups: metav1.APIGroupList{ 65 Groups: []metav1.APIGroup{ 66 { 67 Name: "", 68 Versions: []metav1.GroupVersionForDiscovery{ 69 { 70 GroupVersion: "v1", 71 Version: "v1", 72 }, 73 }, 74 PreferredVersion: metav1.GroupVersionForDiscovery{ 75 GroupVersion: "v1", 76 Version: "v1", 77 }, 78 }, 79 }, 80 }, 81 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 82 {Group: "", Version: "v1"}: { 83 GroupVersion: "v1", 84 APIResources: []metav1.APIResource{ 85 { 86 Name: "pods", 87 Namespaced: true, 88 Group: "", 89 Version: "v1", 90 Kind: "Pod", 91 }, 92 }, 93 }, 94 }, 95 expectedFailedGVs: map[schema.GroupVersion]error{}, 96 }, 97 { 98 name: "Aggregated discovery: 1 group/1 resources at /api, 1 group/2 versions/1 resources at /apis", 99 agg: apidiscovery.APIGroupDiscoveryList{ 100 Items: []apidiscovery.APIGroupDiscovery{ 101 { 102 ObjectMeta: metav1.ObjectMeta{ 103 Name: "apps", 104 }, 105 Versions: []apidiscovery.APIVersionDiscovery{ 106 { 107 Version: "v2", 108 Resources: []apidiscovery.APIResourceDiscovery{ 109 { 110 Resource: "deployments", 111 ResponseKind: &metav1.GroupVersionKind{ 112 Group: "apps", 113 Version: "v2", 114 Kind: "Deployment", 115 }, 116 Scope: apidiscovery.ScopeNamespace, 117 }, 118 }, 119 }, 120 { 121 Version: "v1", 122 Resources: []apidiscovery.APIResourceDiscovery{ 123 { 124 Resource: "deployments", 125 ResponseKind: &metav1.GroupVersionKind{ 126 Group: "apps", 127 Version: "v1", 128 Kind: "Deployment", 129 }, 130 Scope: apidiscovery.ScopeNamespace, 131 }, 132 }, 133 }, 134 }, 135 }, 136 }, 137 }, 138 expectedGroups: metav1.APIGroupList{ 139 Groups: []metav1.APIGroup{ 140 { 141 Name: "apps", 142 Versions: []metav1.GroupVersionForDiscovery{ 143 { 144 GroupVersion: "apps/v2", 145 Version: "v2", 146 }, 147 { 148 GroupVersion: "apps/v1", 149 Version: "v1", 150 }, 151 }, 152 PreferredVersion: metav1.GroupVersionForDiscovery{ 153 GroupVersion: "apps/v2", 154 Version: "v2", 155 }, 156 }, 157 }, 158 }, 159 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 160 {Group: "apps", Version: "v1"}: { 161 GroupVersion: "apps/v1", 162 APIResources: []metav1.APIResource{ 163 { 164 Name: "deployments", 165 Namespaced: true, 166 Group: "apps", 167 Version: "v1", 168 Kind: "Deployment", 169 }, 170 }, 171 }, 172 {Group: "apps", Version: "v2"}: { 173 GroupVersion: "apps/v2", 174 APIResources: []metav1.APIResource{ 175 { 176 Name: "deployments", 177 Namespaced: true, 178 Group: "apps", 179 Version: "v2", 180 Kind: "Deployment", 181 }, 182 }, 183 }, 184 }, 185 expectedFailedGVs: map[schema.GroupVersion]error{}, 186 }, 187 { 188 name: "Aggregated discovery: 1 group/2 resources at /api, 1 group/2 resources at /apis", 189 agg: apidiscovery.APIGroupDiscoveryList{ 190 Items: []apidiscovery.APIGroupDiscovery{ 191 { 192 Versions: []apidiscovery.APIVersionDiscovery{ 193 { 194 Version: "v1", 195 Resources: []apidiscovery.APIResourceDiscovery{ 196 { 197 Resource: "pods", 198 ResponseKind: &metav1.GroupVersionKind{ 199 Group: "", 200 Version: "v1", 201 Kind: "Pod", 202 }, 203 Scope: apidiscovery.ScopeNamespace, 204 }, 205 { 206 Resource: "services", 207 ResponseKind: &metav1.GroupVersionKind{ 208 Group: "", 209 Version: "v1", 210 Kind: "Service", 211 }, 212 Scope: apidiscovery.ScopeNamespace, 213 }, 214 }, 215 }, 216 }, 217 }, 218 { 219 ObjectMeta: metav1.ObjectMeta{ 220 Name: "apps", 221 }, 222 Versions: []apidiscovery.APIVersionDiscovery{ 223 { 224 Version: "v1", 225 Resources: []apidiscovery.APIResourceDiscovery{ 226 { 227 Resource: "deployments", 228 ResponseKind: &metav1.GroupVersionKind{ 229 Group: "apps", 230 Version: "v1", 231 Kind: "Deployment", 232 }, 233 Scope: apidiscovery.ScopeNamespace, 234 }, 235 { 236 Resource: "statefulsets", 237 ResponseKind: &metav1.GroupVersionKind{ 238 Group: "apps", 239 Version: "v1", 240 Kind: "StatefulSet", 241 }, 242 Scope: apidiscovery.ScopeNamespace, 243 }, 244 }, 245 }, 246 }, 247 }, 248 }, 249 }, 250 expectedGroups: metav1.APIGroupList{ 251 Groups: []metav1.APIGroup{ 252 { 253 Name: "", 254 Versions: []metav1.GroupVersionForDiscovery{ 255 { 256 GroupVersion: "v1", 257 Version: "v1", 258 }, 259 }, 260 PreferredVersion: metav1.GroupVersionForDiscovery{ 261 GroupVersion: "v1", 262 Version: "v1", 263 }, 264 }, 265 { 266 Name: "apps", 267 Versions: []metav1.GroupVersionForDiscovery{ 268 { 269 GroupVersion: "apps/v1", 270 Version: "v1", 271 }, 272 }, 273 PreferredVersion: metav1.GroupVersionForDiscovery{ 274 GroupVersion: "apps/v1", 275 Version: "v1", 276 }, 277 }, 278 }, 279 }, 280 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 281 {Group: "", Version: "v1"}: { 282 GroupVersion: "v1", 283 APIResources: []metav1.APIResource{ 284 { 285 Name: "pods", 286 Namespaced: true, 287 Group: "", 288 Version: "v1", 289 Kind: "Pod", 290 }, 291 { 292 Name: "services", 293 Namespaced: true, 294 Group: "", 295 Version: "v1", 296 Kind: "Service", 297 }, 298 }, 299 }, 300 {Group: "apps", Version: "v1"}: { 301 GroupVersion: "apps/v1", 302 APIResources: []metav1.APIResource{ 303 { 304 Name: "deployments", 305 Namespaced: true, 306 Group: "apps", 307 Version: "v1", 308 Kind: "Deployment", 309 }, 310 { 311 Name: "statefulsets", 312 Namespaced: true, 313 Group: "apps", 314 Version: "v1", 315 Kind: "StatefulSet", 316 }, 317 }, 318 }, 319 }, 320 expectedFailedGVs: map[schema.GroupVersion]error{}, 321 }, 322 { 323 name: "Aggregated discovery: multiple groups with cluster-scoped resources", 324 agg: apidiscovery.APIGroupDiscoveryList{ 325 Items: []apidiscovery.APIGroupDiscovery{ 326 { 327 Versions: []apidiscovery.APIVersionDiscovery{ 328 { 329 Version: "v1", 330 Resources: []apidiscovery.APIResourceDiscovery{ 331 { 332 Resource: "pods", 333 ResponseKind: &metav1.GroupVersionKind{ 334 Group: "", 335 Version: "v1", 336 Kind: "Pod", 337 }, 338 Scope: apidiscovery.ScopeNamespace, 339 }, 340 { 341 Resource: "namespaces", 342 ResponseKind: &metav1.GroupVersionKind{ 343 Group: "", 344 Version: "v1", 345 Kind: "Namespace", 346 }, 347 Scope: apidiscovery.ScopeCluster, 348 }, 349 }, 350 }, 351 }, 352 }, 353 { 354 ObjectMeta: metav1.ObjectMeta{ 355 Name: "rbac.authorization.k8s.io", 356 }, 357 Versions: []apidiscovery.APIVersionDiscovery{ 358 { 359 Version: "v1", 360 Resources: []apidiscovery.APIResourceDiscovery{ 361 { 362 Resource: "roles", 363 ResponseKind: &metav1.GroupVersionKind{ 364 Group: "rbac.authorization.k8s.io", 365 Version: "v1", 366 Kind: "Role", 367 }, 368 Scope: apidiscovery.ScopeCluster, 369 }, 370 { 371 Resource: "clusterroles", 372 ResponseKind: &metav1.GroupVersionKind{ 373 Group: "rbac.authorization.k8s.io", 374 Version: "v1", 375 Kind: "ClusterRole", 376 }, 377 Scope: apidiscovery.ScopeCluster, 378 }, 379 }, 380 }, 381 }, 382 }, 383 }, 384 }, 385 expectedGroups: metav1.APIGroupList{ 386 Groups: []metav1.APIGroup{ 387 { 388 Name: "", 389 Versions: []metav1.GroupVersionForDiscovery{ 390 { 391 GroupVersion: "v1", 392 Version: "v1", 393 }, 394 }, 395 PreferredVersion: metav1.GroupVersionForDiscovery{ 396 GroupVersion: "v1", 397 Version: "v1", 398 }, 399 }, 400 { 401 Name: "rbac.authorization.k8s.io", 402 Versions: []metav1.GroupVersionForDiscovery{ 403 { 404 GroupVersion: "rbac.authorization.k8s.io/v1", 405 Version: "v1", 406 }, 407 }, 408 PreferredVersion: metav1.GroupVersionForDiscovery{ 409 GroupVersion: "rbac.authorization.k8s.io/v1", 410 Version: "v1", 411 }, 412 }, 413 }, 414 }, 415 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 416 {Group: "", Version: "v1"}: { 417 GroupVersion: "v1", 418 APIResources: []metav1.APIResource{ 419 { 420 Name: "pods", 421 Namespaced: true, 422 Group: "", 423 Version: "v1", 424 Kind: "Pod", 425 }, 426 { 427 Name: "namespaces", 428 Namespaced: false, 429 Group: "", 430 Version: "v1", 431 Kind: "Namespace", 432 }, 433 }, 434 }, 435 {Group: "rbac.authorization.k8s.io", Version: "v1"}: { 436 GroupVersion: "rbac.authorization.k8s.io/v1", 437 APIResources: []metav1.APIResource{ 438 { 439 Name: "roles", 440 Namespaced: false, 441 Group: "rbac.authorization.k8s.io", 442 Version: "v1", 443 Kind: "Role", 444 }, 445 { 446 Name: "clusterroles", 447 Namespaced: false, 448 Group: "rbac.authorization.k8s.io", 449 Version: "v1", 450 Kind: "ClusterRole", 451 }, 452 }, 453 }, 454 }, 455 expectedFailedGVs: map[schema.GroupVersion]error{}, 456 }, 457 { 458 name: "Aggregated discovery with single subresource", 459 agg: apidiscovery.APIGroupDiscoveryList{ 460 Items: []apidiscovery.APIGroupDiscovery{ 461 { 462 ObjectMeta: metav1.ObjectMeta{ 463 Name: "apps", 464 }, 465 Versions: []apidiscovery.APIVersionDiscovery{ 466 { 467 Version: "v1", 468 Resources: []apidiscovery.APIResourceDiscovery{ 469 { 470 Resource: "deployments", 471 ResponseKind: &metav1.GroupVersionKind{ 472 Group: "apps", 473 Version: "v1", 474 Kind: "Deployment", 475 }, 476 Scope: apidiscovery.ScopeNamespace, 477 SingularResource: "deployment", 478 ShortNames: []string{"deploy"}, 479 Verbs: []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"}, 480 Categories: []string{"all", "testcategory"}, 481 Subresources: []apidiscovery.APISubresourceDiscovery{ 482 { 483 Subresource: "scale", 484 ResponseKind: &metav1.GroupVersionKind{ 485 Group: "apps", 486 Version: "v1", 487 Kind: "Deployment", 488 }, 489 Verbs: []string{"get", "patch", "update"}, 490 }, 491 }, 492 }, 493 }, 494 }, 495 }, 496 }, 497 }, 498 }, 499 expectedGroups: metav1.APIGroupList{ 500 Groups: []metav1.APIGroup{ 501 { 502 Name: "apps", 503 Versions: []metav1.GroupVersionForDiscovery{ 504 { 505 GroupVersion: "apps/v1", 506 Version: "v1", 507 }, 508 }, 509 PreferredVersion: metav1.GroupVersionForDiscovery{ 510 GroupVersion: "apps/v1", 511 Version: "v1", 512 }, 513 }, 514 }, 515 }, 516 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 517 {Group: "apps", Version: "v1"}: { 518 GroupVersion: "apps/v1", 519 APIResources: []metav1.APIResource{ 520 { 521 Name: "deployments", 522 SingularName: "deployment", 523 Namespaced: true, 524 Group: "apps", 525 Version: "v1", 526 Kind: "Deployment", 527 Verbs: []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"}, 528 ShortNames: []string{"deploy"}, 529 Categories: []string{"all", "testcategory"}, 530 }, 531 { 532 Name: "deployments/scale", 533 SingularName: "deployment", 534 Namespaced: true, 535 Group: "apps", 536 Version: "v1", 537 Kind: "Deployment", 538 Verbs: []string{"get", "patch", "update"}, 539 }, 540 }, 541 }, 542 }, 543 expectedFailedGVs: map[schema.GroupVersion]error{}, 544 }, 545 { 546 name: "Aggregated discovery with single subresource and parent missing GVK", 547 agg: apidiscovery.APIGroupDiscoveryList{ 548 Items: []apidiscovery.APIGroupDiscovery{ 549 { 550 ObjectMeta: metav1.ObjectMeta{ 551 Name: "external.metrics.k8s.io", 552 }, 553 Versions: []apidiscovery.APIVersionDiscovery{ 554 { 555 Version: "v1beta1", 556 Resources: []apidiscovery.APIResourceDiscovery{ 557 { 558 // resilient to nil GVK for parent 559 Resource: "*", 560 Scope: apidiscovery.ScopeNamespace, 561 SingularResource: "", 562 Subresources: []apidiscovery.APISubresourceDiscovery{ 563 { 564 Subresource: "other-external-metric", 565 ResponseKind: &metav1.GroupVersionKind{ 566 Kind: "MetricValueList", 567 }, 568 Verbs: []string{"get"}, 569 }, 570 }, 571 }, 572 }, 573 }, 574 }, 575 }, 576 }, 577 }, 578 expectedGroups: metav1.APIGroupList{ 579 Groups: []metav1.APIGroup{ 580 { 581 Name: "external.metrics.k8s.io", 582 Versions: []metav1.GroupVersionForDiscovery{ 583 { 584 GroupVersion: "external.metrics.k8s.io/v1beta1", 585 Version: "v1beta1", 586 }, 587 }, 588 PreferredVersion: metav1.GroupVersionForDiscovery{ 589 GroupVersion: "external.metrics.k8s.io/v1beta1", 590 Version: "v1beta1", 591 }, 592 }, 593 }, 594 }, 595 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 596 {Group: "external.metrics.k8s.io", Version: "v1beta1"}: { 597 GroupVersion: "external.metrics.k8s.io/v1beta1", 598 APIResources: []metav1.APIResource{ 599 // Since parent GVK was nil, it is NOT returned--only the subresource. 600 { 601 Name: "*/other-external-metric", 602 SingularName: "", 603 Namespaced: true, 604 Group: "", 605 Version: "", 606 Kind: "MetricValueList", 607 Verbs: []string{"get"}, 608 }, 609 }, 610 }, 611 }, 612 expectedFailedGVs: map[schema.GroupVersion]error{}, 613 }, 614 { 615 name: "Aggregated discovery with single subresource and parent empty GVK", 616 agg: apidiscovery.APIGroupDiscoveryList{ 617 Items: []apidiscovery.APIGroupDiscovery{ 618 { 619 ObjectMeta: metav1.ObjectMeta{ 620 Name: "external.metrics.k8s.io", 621 }, 622 Versions: []apidiscovery.APIVersionDiscovery{ 623 { 624 Version: "v1beta1", 625 Resources: []apidiscovery.APIResourceDiscovery{ 626 { 627 // resilient to empty GVK for parent 628 Resource: "*", 629 Scope: apidiscovery.ScopeNamespace, 630 SingularResource: "", 631 ResponseKind: &metav1.GroupVersionKind{}, 632 Subresources: []apidiscovery.APISubresourceDiscovery{ 633 { 634 Subresource: "other-external-metric", 635 ResponseKind: &metav1.GroupVersionKind{ 636 Kind: "MetricValueList", 637 }, 638 Verbs: []string{"get"}, 639 }, 640 }, 641 }, 642 }, 643 }, 644 }, 645 }, 646 }, 647 }, 648 expectedGroups: metav1.APIGroupList{ 649 Groups: []metav1.APIGroup{ 650 { 651 Name: "external.metrics.k8s.io", 652 Versions: []metav1.GroupVersionForDiscovery{ 653 { 654 GroupVersion: "external.metrics.k8s.io/v1beta1", 655 Version: "v1beta1", 656 }, 657 }, 658 PreferredVersion: metav1.GroupVersionForDiscovery{ 659 GroupVersion: "external.metrics.k8s.io/v1beta1", 660 Version: "v1beta1", 661 }, 662 }, 663 }, 664 }, 665 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 666 {Group: "external.metrics.k8s.io", Version: "v1beta1"}: { 667 GroupVersion: "external.metrics.k8s.io/v1beta1", 668 APIResources: []metav1.APIResource{ 669 // Since parent GVK was nil, it is NOT returned--only the subresource. 670 { 671 Name: "*/other-external-metric", 672 SingularName: "", 673 Namespaced: true, 674 Group: "", 675 Version: "", 676 Kind: "MetricValueList", 677 Verbs: []string{"get"}, 678 }, 679 }, 680 }, 681 }, 682 expectedFailedGVs: map[schema.GroupVersion]error{}, 683 }, 684 { 685 name: "Aggregated discovery with multiple subresources", 686 agg: apidiscovery.APIGroupDiscoveryList{ 687 Items: []apidiscovery.APIGroupDiscovery{ 688 { 689 ObjectMeta: metav1.ObjectMeta{ 690 Name: "apps", 691 }, 692 Versions: []apidiscovery.APIVersionDiscovery{ 693 { 694 Version: "v1", 695 Resources: []apidiscovery.APIResourceDiscovery{ 696 { 697 Resource: "deployments", 698 ResponseKind: &metav1.GroupVersionKind{ 699 Group: "apps", 700 Version: "v1", 701 Kind: "Deployment", 702 }, 703 Scope: apidiscovery.ScopeNamespace, 704 SingularResource: "deployment", 705 Subresources: []apidiscovery.APISubresourceDiscovery{ 706 { 707 Subresource: "scale", 708 ResponseKind: &metav1.GroupVersionKind{ 709 Group: "apps", 710 Version: "v1", 711 Kind: "Deployment", 712 }, 713 Verbs: []string{"get", "patch", "update"}, 714 }, 715 { 716 Subresource: "status", 717 ResponseKind: &metav1.GroupVersionKind{ 718 Group: "apps", 719 Version: "v1", 720 Kind: "Deployment", 721 }, 722 Verbs: []string{"get", "patch", "update"}, 723 }, 724 }, 725 }, 726 }, 727 }, 728 }, 729 }, 730 }, 731 }, 732 expectedGroups: metav1.APIGroupList{ 733 Groups: []metav1.APIGroup{ 734 { 735 Name: "apps", 736 Versions: []metav1.GroupVersionForDiscovery{ 737 { 738 GroupVersion: "apps/v1", 739 Version: "v1", 740 }, 741 }, 742 PreferredVersion: metav1.GroupVersionForDiscovery{ 743 GroupVersion: "apps/v1", 744 Version: "v1", 745 }, 746 }, 747 }, 748 }, 749 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 750 {Group: "apps", Version: "v1"}: { 751 GroupVersion: "apps/v1", 752 APIResources: []metav1.APIResource{ 753 { 754 Name: "deployments", 755 SingularName: "deployment", 756 Namespaced: true, 757 Group: "apps", 758 Version: "v1", 759 Kind: "Deployment", 760 }, 761 { 762 Name: "deployments/scale", 763 SingularName: "deployment", 764 Namespaced: true, 765 Group: "apps", 766 Version: "v1", 767 Kind: "Deployment", 768 Verbs: []string{"get", "patch", "update"}, 769 }, 770 { 771 Name: "deployments/status", 772 SingularName: "deployment", 773 Namespaced: true, 774 Group: "apps", 775 Version: "v1", 776 Kind: "Deployment", 777 Verbs: []string{"get", "patch", "update"}, 778 }, 779 }, 780 }, 781 }, 782 expectedFailedGVs: map[schema.GroupVersion]error{}, 783 }, 784 { 785 name: "Aggregated discovery: single failed GV at /api", 786 agg: apidiscovery.APIGroupDiscoveryList{ 787 Items: []apidiscovery.APIGroupDiscovery{ 788 { 789 Versions: []apidiscovery.APIVersionDiscovery{ 790 { 791 Version: "v1", 792 Resources: []apidiscovery.APIResourceDiscovery{ 793 { 794 Resource: "pods", 795 ResponseKind: &metav1.GroupVersionKind{ 796 Group: "", 797 Version: "v1", 798 Kind: "Pod", 799 }, 800 Scope: apidiscovery.ScopeNamespace, 801 }, 802 { 803 Resource: "services", 804 ResponseKind: &metav1.GroupVersionKind{ 805 Group: "", 806 Version: "v1", 807 Kind: "Service", 808 }, 809 Scope: apidiscovery.ScopeNamespace, 810 }, 811 }, 812 Freshness: apidiscovery.DiscoveryFreshnessStale, 813 }, 814 }, 815 }, 816 }, 817 }, 818 // Single core Group/Version is stale, so no Version within Group. 819 expectedGroups: metav1.APIGroupList{ 820 Groups: []metav1.APIGroup{{Name: ""}}, 821 }, 822 // Single core Group/Version is stale, so there are no expected resources. 823 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{}, 824 expectedFailedGVs: map[schema.GroupVersion]error{ 825 {Group: "", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "", Version: "v1"}}, 826 }, 827 }, 828 { 829 name: "Aggregated discovery: single failed GV at /apis", 830 agg: apidiscovery.APIGroupDiscoveryList{ 831 Items: []apidiscovery.APIGroupDiscovery{ 832 { 833 ObjectMeta: metav1.ObjectMeta{ 834 Name: "apps", 835 }, 836 Versions: []apidiscovery.APIVersionDiscovery{ 837 { 838 Version: "v1", 839 Resources: []apidiscovery.APIResourceDiscovery{ 840 { 841 Resource: "deployments", 842 ResponseKind: &metav1.GroupVersionKind{ 843 Group: "apps", 844 Version: "v1", 845 Kind: "Deployment", 846 }, 847 Scope: apidiscovery.ScopeNamespace, 848 }, 849 { 850 Resource: "statefulsets", 851 ResponseKind: &metav1.GroupVersionKind{ 852 Group: "apps", 853 Version: "v1", 854 Kind: "StatefulSets", 855 }, 856 Scope: apidiscovery.ScopeNamespace, 857 }, 858 }, 859 Freshness: apidiscovery.DiscoveryFreshnessStale, 860 }, 861 }, 862 }, 863 }, 864 }, 865 // Single apps/v1 Group/Version is stale, so no Version within Group. 866 expectedGroups: metav1.APIGroupList{ 867 Groups: []metav1.APIGroup{{Name: "apps"}}, 868 }, 869 // Single apps/v1 Group/Version is stale, so there are no expected resources. 870 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{}, 871 expectedFailedGVs: map[schema.GroupVersion]error{ 872 {Group: "apps", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v1"}}, 873 }, 874 }, 875 { 876 name: "Aggregated discovery: 1 group/2 versions/1 failed GV at /apis", 877 agg: apidiscovery.APIGroupDiscoveryList{ 878 Items: []apidiscovery.APIGroupDiscovery{ 879 { 880 ObjectMeta: metav1.ObjectMeta{ 881 Name: "apps", 882 }, 883 Versions: []apidiscovery.APIVersionDiscovery{ 884 // Stale v2 should report failed GV. 885 { 886 Version: "v2", 887 Resources: []apidiscovery.APIResourceDiscovery{ 888 { 889 Resource: "daemonsets", 890 ResponseKind: &metav1.GroupVersionKind{ 891 Group: "apps", 892 Version: "v2", 893 Kind: "DaemonSets", 894 }, 895 Scope: apidiscovery.ScopeNamespace, 896 }, 897 }, 898 Freshness: apidiscovery.DiscoveryFreshnessStale, 899 }, 900 { 901 Version: "v1", 902 Resources: []apidiscovery.APIResourceDiscovery{ 903 { 904 Resource: "deployments", 905 ResponseKind: &metav1.GroupVersionKind{ 906 Group: "apps", 907 Version: "v1", 908 Kind: "Deployment", 909 }, 910 Scope: apidiscovery.ScopeNamespace, 911 }, 912 }, 913 }, 914 }, 915 }, 916 }, 917 }, 918 // Only apps/v1 is non-stale expected Group/Version 919 expectedGroups: metav1.APIGroupList{ 920 Groups: []metav1.APIGroup{ 921 { 922 Name: "apps", 923 Versions: []metav1.GroupVersionForDiscovery{ 924 { 925 GroupVersion: "apps/v1", 926 Version: "v1", 927 }, 928 }, 929 // PreferredVersion must be apps/v1 930 PreferredVersion: metav1.GroupVersionForDiscovery{ 931 GroupVersion: "apps/v1", 932 Version: "v1", 933 }, 934 }, 935 }, 936 }, 937 // Only apps/v1 resources expected. 938 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 939 {Group: "apps", Version: "v1"}: { 940 GroupVersion: "apps/v1", 941 APIResources: []metav1.APIResource{ 942 { 943 Name: "deployments", 944 Namespaced: true, 945 Group: "apps", 946 Version: "v1", 947 Kind: "Deployment", 948 }, 949 }, 950 }, 951 }, 952 expectedFailedGVs: map[schema.GroupVersion]error{ 953 {Group: "apps", Version: "v2"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v2"}}, 954 }, 955 }, 956 } 957 958 for _, test := range tests { 959 apiGroups, resourcesByGV, failedGVs := SplitGroupsAndResources(test.agg) 960 assert.Equal(t, test.expectedFailedGVs, failedGVs) 961 assert.Equal(t, test.expectedGroups, *apiGroups) 962 assert.Equal(t, test.expectedGVResources, resourcesByGV) 963 } 964 } 965 966 // Duplicated from test above. Remove after 1.33 967 func TestSplitGroupsAndResourcesV2Beta1(t *testing.T) { 968 tests := []struct { 969 name string 970 agg apidiscoveryv2beta1.APIGroupDiscoveryList 971 expectedGroups metav1.APIGroupList 972 expectedGVResources map[schema.GroupVersion]*metav1.APIResourceList 973 expectedFailedGVs map[schema.GroupVersion]error 974 }{ 975 { 976 name: "Aggregated discovery: core/v1 group and pod resource", 977 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 978 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 979 { 980 ObjectMeta: metav1.ObjectMeta{ 981 Name: "", 982 }, 983 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 984 { 985 Version: "v1", 986 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 987 { 988 Resource: "pods", 989 ResponseKind: &metav1.GroupVersionKind{ 990 Group: "", 991 Version: "v1", 992 Kind: "Pod", 993 }, 994 Scope: apidiscoveryv2beta1.ScopeNamespace, 995 }, 996 }, 997 }, 998 }, 999 }, 1000 }, 1001 }, 1002 expectedGroups: metav1.APIGroupList{ 1003 Groups: []metav1.APIGroup{ 1004 { 1005 Name: "", 1006 Versions: []metav1.GroupVersionForDiscovery{ 1007 { 1008 GroupVersion: "v1", 1009 Version: "v1", 1010 }, 1011 }, 1012 PreferredVersion: metav1.GroupVersionForDiscovery{ 1013 GroupVersion: "v1", 1014 Version: "v1", 1015 }, 1016 }, 1017 }, 1018 }, 1019 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1020 {Group: "", Version: "v1"}: { 1021 GroupVersion: "v1", 1022 APIResources: []metav1.APIResource{ 1023 { 1024 Name: "pods", 1025 Namespaced: true, 1026 Group: "", 1027 Version: "v1", 1028 Kind: "Pod", 1029 }, 1030 }, 1031 }, 1032 }, 1033 expectedFailedGVs: map[schema.GroupVersion]error{}, 1034 }, 1035 { 1036 name: "Aggregated discovery: 1 group/1 resources at /api, 1 group/2 versions/1 resources at /apis", 1037 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1038 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1039 { 1040 ObjectMeta: metav1.ObjectMeta{ 1041 Name: "apps", 1042 }, 1043 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1044 { 1045 Version: "v2", 1046 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1047 { 1048 Resource: "deployments", 1049 ResponseKind: &metav1.GroupVersionKind{ 1050 Group: "apps", 1051 Version: "v2", 1052 Kind: "Deployment", 1053 }, 1054 Scope: apidiscoveryv2beta1.ScopeNamespace, 1055 }, 1056 }, 1057 }, 1058 { 1059 Version: "v1", 1060 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1061 { 1062 Resource: "deployments", 1063 ResponseKind: &metav1.GroupVersionKind{ 1064 Group: "apps", 1065 Version: "v1", 1066 Kind: "Deployment", 1067 }, 1068 Scope: apidiscoveryv2beta1.ScopeNamespace, 1069 }, 1070 }, 1071 }, 1072 }, 1073 }, 1074 }, 1075 }, 1076 expectedGroups: metav1.APIGroupList{ 1077 Groups: []metav1.APIGroup{ 1078 { 1079 Name: "apps", 1080 Versions: []metav1.GroupVersionForDiscovery{ 1081 { 1082 GroupVersion: "apps/v2", 1083 Version: "v2", 1084 }, 1085 { 1086 GroupVersion: "apps/v1", 1087 Version: "v1", 1088 }, 1089 }, 1090 PreferredVersion: metav1.GroupVersionForDiscovery{ 1091 GroupVersion: "apps/v2", 1092 Version: "v2", 1093 }, 1094 }, 1095 }, 1096 }, 1097 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1098 {Group: "apps", Version: "v1"}: { 1099 GroupVersion: "apps/v1", 1100 APIResources: []metav1.APIResource{ 1101 { 1102 Name: "deployments", 1103 Namespaced: true, 1104 Group: "apps", 1105 Version: "v1", 1106 Kind: "Deployment", 1107 }, 1108 }, 1109 }, 1110 {Group: "apps", Version: "v2"}: { 1111 GroupVersion: "apps/v2", 1112 APIResources: []metav1.APIResource{ 1113 { 1114 Name: "deployments", 1115 Namespaced: true, 1116 Group: "apps", 1117 Version: "v2", 1118 Kind: "Deployment", 1119 }, 1120 }, 1121 }, 1122 }, 1123 expectedFailedGVs: map[schema.GroupVersion]error{}, 1124 }, 1125 { 1126 name: "Aggregated discovery: 1 group/2 resources at /api, 1 group/2 resources at /apis", 1127 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1128 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1129 { 1130 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1131 { 1132 Version: "v1", 1133 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1134 { 1135 Resource: "pods", 1136 ResponseKind: &metav1.GroupVersionKind{ 1137 Group: "", 1138 Version: "v1", 1139 Kind: "Pod", 1140 }, 1141 Scope: apidiscoveryv2beta1.ScopeNamespace, 1142 }, 1143 { 1144 Resource: "services", 1145 ResponseKind: &metav1.GroupVersionKind{ 1146 Group: "", 1147 Version: "v1", 1148 Kind: "Service", 1149 }, 1150 Scope: apidiscoveryv2beta1.ScopeNamespace, 1151 }, 1152 }, 1153 }, 1154 }, 1155 }, 1156 { 1157 ObjectMeta: metav1.ObjectMeta{ 1158 Name: "apps", 1159 }, 1160 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1161 { 1162 Version: "v1", 1163 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1164 { 1165 Resource: "deployments", 1166 ResponseKind: &metav1.GroupVersionKind{ 1167 Group: "apps", 1168 Version: "v1", 1169 Kind: "Deployment", 1170 }, 1171 Scope: apidiscoveryv2beta1.ScopeNamespace, 1172 }, 1173 { 1174 Resource: "statefulsets", 1175 ResponseKind: &metav1.GroupVersionKind{ 1176 Group: "apps", 1177 Version: "v1", 1178 Kind: "StatefulSet", 1179 }, 1180 Scope: apidiscoveryv2beta1.ScopeNamespace, 1181 }, 1182 }, 1183 }, 1184 }, 1185 }, 1186 }, 1187 }, 1188 expectedGroups: metav1.APIGroupList{ 1189 Groups: []metav1.APIGroup{ 1190 { 1191 Name: "", 1192 Versions: []metav1.GroupVersionForDiscovery{ 1193 { 1194 GroupVersion: "v1", 1195 Version: "v1", 1196 }, 1197 }, 1198 PreferredVersion: metav1.GroupVersionForDiscovery{ 1199 GroupVersion: "v1", 1200 Version: "v1", 1201 }, 1202 }, 1203 { 1204 Name: "apps", 1205 Versions: []metav1.GroupVersionForDiscovery{ 1206 { 1207 GroupVersion: "apps/v1", 1208 Version: "v1", 1209 }, 1210 }, 1211 PreferredVersion: metav1.GroupVersionForDiscovery{ 1212 GroupVersion: "apps/v1", 1213 Version: "v1", 1214 }, 1215 }, 1216 }, 1217 }, 1218 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1219 {Group: "", Version: "v1"}: { 1220 GroupVersion: "v1", 1221 APIResources: []metav1.APIResource{ 1222 { 1223 Name: "pods", 1224 Namespaced: true, 1225 Group: "", 1226 Version: "v1", 1227 Kind: "Pod", 1228 }, 1229 { 1230 Name: "services", 1231 Namespaced: true, 1232 Group: "", 1233 Version: "v1", 1234 Kind: "Service", 1235 }, 1236 }, 1237 }, 1238 {Group: "apps", Version: "v1"}: { 1239 GroupVersion: "apps/v1", 1240 APIResources: []metav1.APIResource{ 1241 { 1242 Name: "deployments", 1243 Namespaced: true, 1244 Group: "apps", 1245 Version: "v1", 1246 Kind: "Deployment", 1247 }, 1248 { 1249 Name: "statefulsets", 1250 Namespaced: true, 1251 Group: "apps", 1252 Version: "v1", 1253 Kind: "StatefulSet", 1254 }, 1255 }, 1256 }, 1257 }, 1258 expectedFailedGVs: map[schema.GroupVersion]error{}, 1259 }, 1260 { 1261 name: "Aggregated discovery: multiple groups with cluster-scoped resources", 1262 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1263 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1264 { 1265 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1266 { 1267 Version: "v1", 1268 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1269 { 1270 Resource: "pods", 1271 ResponseKind: &metav1.GroupVersionKind{ 1272 Group: "", 1273 Version: "v1", 1274 Kind: "Pod", 1275 }, 1276 Scope: apidiscoveryv2beta1.ScopeNamespace, 1277 }, 1278 { 1279 Resource: "namespaces", 1280 ResponseKind: &metav1.GroupVersionKind{ 1281 Group: "", 1282 Version: "v1", 1283 Kind: "Namespace", 1284 }, 1285 Scope: apidiscoveryv2beta1.ScopeCluster, 1286 }, 1287 }, 1288 }, 1289 }, 1290 }, 1291 { 1292 ObjectMeta: metav1.ObjectMeta{ 1293 Name: "rbac.authorization.k8s.io", 1294 }, 1295 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1296 { 1297 Version: "v1", 1298 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1299 { 1300 Resource: "roles", 1301 ResponseKind: &metav1.GroupVersionKind{ 1302 Group: "rbac.authorization.k8s.io", 1303 Version: "v1", 1304 Kind: "Role", 1305 }, 1306 Scope: apidiscoveryv2beta1.ScopeCluster, 1307 }, 1308 { 1309 Resource: "clusterroles", 1310 ResponseKind: &metav1.GroupVersionKind{ 1311 Group: "rbac.authorization.k8s.io", 1312 Version: "v1", 1313 Kind: "ClusterRole", 1314 }, 1315 Scope: apidiscoveryv2beta1.ScopeCluster, 1316 }, 1317 }, 1318 }, 1319 }, 1320 }, 1321 }, 1322 }, 1323 expectedGroups: metav1.APIGroupList{ 1324 Groups: []metav1.APIGroup{ 1325 { 1326 Name: "", 1327 Versions: []metav1.GroupVersionForDiscovery{ 1328 { 1329 GroupVersion: "v1", 1330 Version: "v1", 1331 }, 1332 }, 1333 PreferredVersion: metav1.GroupVersionForDiscovery{ 1334 GroupVersion: "v1", 1335 Version: "v1", 1336 }, 1337 }, 1338 { 1339 Name: "rbac.authorization.k8s.io", 1340 Versions: []metav1.GroupVersionForDiscovery{ 1341 { 1342 GroupVersion: "rbac.authorization.k8s.io/v1", 1343 Version: "v1", 1344 }, 1345 }, 1346 PreferredVersion: metav1.GroupVersionForDiscovery{ 1347 GroupVersion: "rbac.authorization.k8s.io/v1", 1348 Version: "v1", 1349 }, 1350 }, 1351 }, 1352 }, 1353 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1354 {Group: "", Version: "v1"}: { 1355 GroupVersion: "v1", 1356 APIResources: []metav1.APIResource{ 1357 { 1358 Name: "pods", 1359 Namespaced: true, 1360 Group: "", 1361 Version: "v1", 1362 Kind: "Pod", 1363 }, 1364 { 1365 Name: "namespaces", 1366 Namespaced: false, 1367 Group: "", 1368 Version: "v1", 1369 Kind: "Namespace", 1370 }, 1371 }, 1372 }, 1373 {Group: "rbac.authorization.k8s.io", Version: "v1"}: { 1374 GroupVersion: "rbac.authorization.k8s.io/v1", 1375 APIResources: []metav1.APIResource{ 1376 { 1377 Name: "roles", 1378 Namespaced: false, 1379 Group: "rbac.authorization.k8s.io", 1380 Version: "v1", 1381 Kind: "Role", 1382 }, 1383 { 1384 Name: "clusterroles", 1385 Namespaced: false, 1386 Group: "rbac.authorization.k8s.io", 1387 Version: "v1", 1388 Kind: "ClusterRole", 1389 }, 1390 }, 1391 }, 1392 }, 1393 expectedFailedGVs: map[schema.GroupVersion]error{}, 1394 }, 1395 { 1396 name: "Aggregated discovery with single subresource", 1397 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1398 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1399 { 1400 ObjectMeta: metav1.ObjectMeta{ 1401 Name: "apps", 1402 }, 1403 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1404 { 1405 Version: "v1", 1406 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1407 { 1408 Resource: "deployments", 1409 ResponseKind: &metav1.GroupVersionKind{ 1410 Group: "apps", 1411 Version: "v1", 1412 Kind: "Deployment", 1413 }, 1414 Scope: apidiscoveryv2beta1.ScopeNamespace, 1415 SingularResource: "deployment", 1416 ShortNames: []string{"deploy"}, 1417 Verbs: []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"}, 1418 Categories: []string{"all", "testcategory"}, 1419 Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{ 1420 { 1421 Subresource: "scale", 1422 ResponseKind: &metav1.GroupVersionKind{ 1423 Group: "apps", 1424 Version: "v1", 1425 Kind: "Deployment", 1426 }, 1427 Verbs: []string{"get", "patch", "update"}, 1428 }, 1429 }, 1430 }, 1431 }, 1432 }, 1433 }, 1434 }, 1435 }, 1436 }, 1437 expectedGroups: metav1.APIGroupList{ 1438 Groups: []metav1.APIGroup{ 1439 { 1440 Name: "apps", 1441 Versions: []metav1.GroupVersionForDiscovery{ 1442 { 1443 GroupVersion: "apps/v1", 1444 Version: "v1", 1445 }, 1446 }, 1447 PreferredVersion: metav1.GroupVersionForDiscovery{ 1448 GroupVersion: "apps/v1", 1449 Version: "v1", 1450 }, 1451 }, 1452 }, 1453 }, 1454 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1455 {Group: "apps", Version: "v1"}: { 1456 GroupVersion: "apps/v1", 1457 APIResources: []metav1.APIResource{ 1458 { 1459 Name: "deployments", 1460 SingularName: "deployment", 1461 Namespaced: true, 1462 Group: "apps", 1463 Version: "v1", 1464 Kind: "Deployment", 1465 Verbs: []string{"parentverb1", "parentverb2", "parentverb3", "parentverb4"}, 1466 ShortNames: []string{"deploy"}, 1467 Categories: []string{"all", "testcategory"}, 1468 }, 1469 { 1470 Name: "deployments/scale", 1471 SingularName: "deployment", 1472 Namespaced: true, 1473 Group: "apps", 1474 Version: "v1", 1475 Kind: "Deployment", 1476 Verbs: []string{"get", "patch", "update"}, 1477 }, 1478 }, 1479 }, 1480 }, 1481 expectedFailedGVs: map[schema.GroupVersion]error{}, 1482 }, 1483 { 1484 name: "Aggregated discovery with single subresource and parent missing GVK", 1485 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1486 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1487 { 1488 ObjectMeta: metav1.ObjectMeta{ 1489 Name: "external.metrics.k8s.io", 1490 }, 1491 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1492 { 1493 Version: "v1beta1", 1494 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1495 { 1496 // resilient to nil GVK for parent 1497 Resource: "*", 1498 Scope: apidiscoveryv2beta1.ScopeNamespace, 1499 SingularResource: "", 1500 Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{ 1501 { 1502 Subresource: "other-external-metric", 1503 ResponseKind: &metav1.GroupVersionKind{ 1504 Kind: "MetricValueList", 1505 }, 1506 Verbs: []string{"get"}, 1507 }, 1508 }, 1509 }, 1510 }, 1511 }, 1512 }, 1513 }, 1514 }, 1515 }, 1516 expectedGroups: metav1.APIGroupList{ 1517 Groups: []metav1.APIGroup{ 1518 { 1519 Name: "external.metrics.k8s.io", 1520 Versions: []metav1.GroupVersionForDiscovery{ 1521 { 1522 GroupVersion: "external.metrics.k8s.io/v1beta1", 1523 Version: "v1beta1", 1524 }, 1525 }, 1526 PreferredVersion: metav1.GroupVersionForDiscovery{ 1527 GroupVersion: "external.metrics.k8s.io/v1beta1", 1528 Version: "v1beta1", 1529 }, 1530 }, 1531 }, 1532 }, 1533 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1534 {Group: "external.metrics.k8s.io", Version: "v1beta1"}: { 1535 GroupVersion: "external.metrics.k8s.io/v1beta1", 1536 APIResources: []metav1.APIResource{ 1537 // Since parent GVK was nil, it is NOT returned--only the subresource. 1538 { 1539 Name: "*/other-external-metric", 1540 SingularName: "", 1541 Namespaced: true, 1542 Group: "", 1543 Version: "", 1544 Kind: "MetricValueList", 1545 Verbs: []string{"get"}, 1546 }, 1547 }, 1548 }, 1549 }, 1550 expectedFailedGVs: map[schema.GroupVersion]error{}, 1551 }, 1552 { 1553 name: "Aggregated discovery with single subresource and parent empty GVK", 1554 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1555 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1556 { 1557 ObjectMeta: metav1.ObjectMeta{ 1558 Name: "external.metrics.k8s.io", 1559 }, 1560 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1561 { 1562 Version: "v1beta1", 1563 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1564 { 1565 // resilient to empty GVK for parent 1566 Resource: "*", 1567 Scope: apidiscoveryv2beta1.ScopeNamespace, 1568 SingularResource: "", 1569 ResponseKind: &metav1.GroupVersionKind{}, 1570 Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{ 1571 { 1572 Subresource: "other-external-metric", 1573 ResponseKind: &metav1.GroupVersionKind{ 1574 Kind: "MetricValueList", 1575 }, 1576 Verbs: []string{"get"}, 1577 }, 1578 }, 1579 }, 1580 }, 1581 }, 1582 }, 1583 }, 1584 }, 1585 }, 1586 expectedGroups: metav1.APIGroupList{ 1587 Groups: []metav1.APIGroup{ 1588 { 1589 Name: "external.metrics.k8s.io", 1590 Versions: []metav1.GroupVersionForDiscovery{ 1591 { 1592 GroupVersion: "external.metrics.k8s.io/v1beta1", 1593 Version: "v1beta1", 1594 }, 1595 }, 1596 PreferredVersion: metav1.GroupVersionForDiscovery{ 1597 GroupVersion: "external.metrics.k8s.io/v1beta1", 1598 Version: "v1beta1", 1599 }, 1600 }, 1601 }, 1602 }, 1603 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1604 {Group: "external.metrics.k8s.io", Version: "v1beta1"}: { 1605 GroupVersion: "external.metrics.k8s.io/v1beta1", 1606 APIResources: []metav1.APIResource{ 1607 // Since parent GVK was nil, it is NOT returned--only the subresource. 1608 { 1609 Name: "*/other-external-metric", 1610 SingularName: "", 1611 Namespaced: true, 1612 Group: "", 1613 Version: "", 1614 Kind: "MetricValueList", 1615 Verbs: []string{"get"}, 1616 }, 1617 }, 1618 }, 1619 }, 1620 expectedFailedGVs: map[schema.GroupVersion]error{}, 1621 }, 1622 { 1623 name: "Aggregated discovery with multiple subresources", 1624 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1625 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1626 { 1627 ObjectMeta: metav1.ObjectMeta{ 1628 Name: "apps", 1629 }, 1630 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1631 { 1632 Version: "v1", 1633 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1634 { 1635 Resource: "deployments", 1636 ResponseKind: &metav1.GroupVersionKind{ 1637 Group: "apps", 1638 Version: "v1", 1639 Kind: "Deployment", 1640 }, 1641 Scope: apidiscoveryv2beta1.ScopeNamespace, 1642 SingularResource: "deployment", 1643 Subresources: []apidiscoveryv2beta1.APISubresourceDiscovery{ 1644 { 1645 Subresource: "scale", 1646 ResponseKind: &metav1.GroupVersionKind{ 1647 Group: "apps", 1648 Version: "v1", 1649 Kind: "Deployment", 1650 }, 1651 Verbs: []string{"get", "patch", "update"}, 1652 }, 1653 { 1654 Subresource: "status", 1655 ResponseKind: &metav1.GroupVersionKind{ 1656 Group: "apps", 1657 Version: "v1", 1658 Kind: "Deployment", 1659 }, 1660 Verbs: []string{"get", "patch", "update"}, 1661 }, 1662 }, 1663 }, 1664 }, 1665 }, 1666 }, 1667 }, 1668 }, 1669 }, 1670 expectedGroups: metav1.APIGroupList{ 1671 Groups: []metav1.APIGroup{ 1672 { 1673 Name: "apps", 1674 Versions: []metav1.GroupVersionForDiscovery{ 1675 { 1676 GroupVersion: "apps/v1", 1677 Version: "v1", 1678 }, 1679 }, 1680 PreferredVersion: metav1.GroupVersionForDiscovery{ 1681 GroupVersion: "apps/v1", 1682 Version: "v1", 1683 }, 1684 }, 1685 }, 1686 }, 1687 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1688 {Group: "apps", Version: "v1"}: { 1689 GroupVersion: "apps/v1", 1690 APIResources: []metav1.APIResource{ 1691 { 1692 Name: "deployments", 1693 SingularName: "deployment", 1694 Namespaced: true, 1695 Group: "apps", 1696 Version: "v1", 1697 Kind: "Deployment", 1698 }, 1699 { 1700 Name: "deployments/scale", 1701 SingularName: "deployment", 1702 Namespaced: true, 1703 Group: "apps", 1704 Version: "v1", 1705 Kind: "Deployment", 1706 Verbs: []string{"get", "patch", "update"}, 1707 }, 1708 { 1709 Name: "deployments/status", 1710 SingularName: "deployment", 1711 Namespaced: true, 1712 Group: "apps", 1713 Version: "v1", 1714 Kind: "Deployment", 1715 Verbs: []string{"get", "patch", "update"}, 1716 }, 1717 }, 1718 }, 1719 }, 1720 expectedFailedGVs: map[schema.GroupVersion]error{}, 1721 }, 1722 { 1723 name: "Aggregated discovery: single failed GV at /api", 1724 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1725 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1726 { 1727 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1728 { 1729 Version: "v1", 1730 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1731 { 1732 Resource: "pods", 1733 ResponseKind: &metav1.GroupVersionKind{ 1734 Group: "", 1735 Version: "v1", 1736 Kind: "Pod", 1737 }, 1738 Scope: apidiscoveryv2beta1.ScopeNamespace, 1739 }, 1740 { 1741 Resource: "services", 1742 ResponseKind: &metav1.GroupVersionKind{ 1743 Group: "", 1744 Version: "v1", 1745 Kind: "Service", 1746 }, 1747 Scope: apidiscoveryv2beta1.ScopeNamespace, 1748 }, 1749 }, 1750 Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale, 1751 }, 1752 }, 1753 }, 1754 }, 1755 }, 1756 // Single core Group/Version is stale, so no Version within Group. 1757 expectedGroups: metav1.APIGroupList{ 1758 Groups: []metav1.APIGroup{{Name: ""}}, 1759 }, 1760 // Single core Group/Version is stale, so there are no expected resources. 1761 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{}, 1762 expectedFailedGVs: map[schema.GroupVersion]error{ 1763 {Group: "", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "", Version: "v1"}}, 1764 }, 1765 }, 1766 { 1767 name: "Aggregated discovery: single failed GV at /apis", 1768 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1769 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1770 { 1771 ObjectMeta: metav1.ObjectMeta{ 1772 Name: "apps", 1773 }, 1774 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1775 { 1776 Version: "v1", 1777 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1778 { 1779 Resource: "deployments", 1780 ResponseKind: &metav1.GroupVersionKind{ 1781 Group: "apps", 1782 Version: "v1", 1783 Kind: "Deployment", 1784 }, 1785 Scope: apidiscoveryv2beta1.ScopeNamespace, 1786 }, 1787 { 1788 Resource: "statefulsets", 1789 ResponseKind: &metav1.GroupVersionKind{ 1790 Group: "apps", 1791 Version: "v1", 1792 Kind: "StatefulSets", 1793 }, 1794 Scope: apidiscoveryv2beta1.ScopeNamespace, 1795 }, 1796 }, 1797 Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale, 1798 }, 1799 }, 1800 }, 1801 }, 1802 }, 1803 // Single apps/v1 Group/Version is stale, so no Version within Group. 1804 expectedGroups: metav1.APIGroupList{ 1805 Groups: []metav1.APIGroup{{Name: "apps"}}, 1806 }, 1807 // Single apps/v1 Group/Version is stale, so there are no expected resources. 1808 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{}, 1809 expectedFailedGVs: map[schema.GroupVersion]error{ 1810 {Group: "apps", Version: "v1"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v1"}}, 1811 }, 1812 }, 1813 { 1814 name: "Aggregated discovery: 1 group/2 versions/1 failed GV at /apis", 1815 agg: apidiscoveryv2beta1.APIGroupDiscoveryList{ 1816 Items: []apidiscoveryv2beta1.APIGroupDiscovery{ 1817 { 1818 ObjectMeta: metav1.ObjectMeta{ 1819 Name: "apps", 1820 }, 1821 Versions: []apidiscoveryv2beta1.APIVersionDiscovery{ 1822 // Stale v2 should report failed GV. 1823 { 1824 Version: "v2", 1825 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1826 { 1827 Resource: "daemonsets", 1828 ResponseKind: &metav1.GroupVersionKind{ 1829 Group: "apps", 1830 Version: "v2", 1831 Kind: "DaemonSets", 1832 }, 1833 Scope: apidiscoveryv2beta1.ScopeNamespace, 1834 }, 1835 }, 1836 Freshness: apidiscoveryv2beta1.DiscoveryFreshnessStale, 1837 }, 1838 { 1839 Version: "v1", 1840 Resources: []apidiscoveryv2beta1.APIResourceDiscovery{ 1841 { 1842 Resource: "deployments", 1843 ResponseKind: &metav1.GroupVersionKind{ 1844 Group: "apps", 1845 Version: "v1", 1846 Kind: "Deployment", 1847 }, 1848 Scope: apidiscoveryv2beta1.ScopeNamespace, 1849 }, 1850 }, 1851 }, 1852 }, 1853 }, 1854 }, 1855 }, 1856 // Only apps/v1 is non-stale expected Group/Version 1857 expectedGroups: metav1.APIGroupList{ 1858 Groups: []metav1.APIGroup{ 1859 { 1860 Name: "apps", 1861 Versions: []metav1.GroupVersionForDiscovery{ 1862 { 1863 GroupVersion: "apps/v1", 1864 Version: "v1", 1865 }, 1866 }, 1867 // PreferredVersion must be apps/v1 1868 PreferredVersion: metav1.GroupVersionForDiscovery{ 1869 GroupVersion: "apps/v1", 1870 Version: "v1", 1871 }, 1872 }, 1873 }, 1874 }, 1875 // Only apps/v1 resources expected. 1876 expectedGVResources: map[schema.GroupVersion]*metav1.APIResourceList{ 1877 {Group: "apps", Version: "v1"}: { 1878 GroupVersion: "apps/v1", 1879 APIResources: []metav1.APIResource{ 1880 { 1881 Name: "deployments", 1882 Namespaced: true, 1883 Group: "apps", 1884 Version: "v1", 1885 Kind: "Deployment", 1886 }, 1887 }, 1888 }, 1889 }, 1890 expectedFailedGVs: map[schema.GroupVersion]error{ 1891 {Group: "apps", Version: "v2"}: StaleGroupVersionError{gv: schema.GroupVersion{Group: "apps", Version: "v2"}}, 1892 }, 1893 }, 1894 } 1895 1896 for _, test := range tests { 1897 apiGroups, resourcesByGV, failedGVs := SplitGroupsAndResourcesV2Beta1(test.agg) 1898 assert.Equal(t, test.expectedFailedGVs, failedGVs) 1899 assert.Equal(t, test.expectedGroups, *apiGroups) 1900 assert.Equal(t, test.expectedGVResources, resourcesByGV) 1901 } 1902 }