k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-controller-manager/app/core_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 app 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/client-go/discovery" 26 fakediscovery "k8s.io/client-go/discovery/fake" 27 "k8s.io/client-go/informers" 28 clientset "k8s.io/client-go/kubernetes" 29 fakeclientset "k8s.io/client-go/kubernetes/fake" 30 restclient "k8s.io/client-go/rest" 31 ) 32 33 // TestClientBuilder inherits ClientBuilder and can accept a given fake clientset. 34 type TestClientBuilder struct { 35 clientset clientset.Interface 36 } 37 38 func (TestClientBuilder) Config(name string) (*restclient.Config, error) { return nil, nil } 39 func (TestClientBuilder) ConfigOrDie(name string) *restclient.Config { 40 return &restclient.Config{} 41 } 42 43 func (TestClientBuilder) Client(name string) (clientset.Interface, error) { return nil, nil } 44 func (m TestClientBuilder) ClientOrDie(name string) clientset.Interface { 45 return m.clientset 46 } 47 48 func (m TestClientBuilder) DiscoveryClient(name string) (discovery.DiscoveryInterface, error) { 49 return m.clientset.Discovery(), nil 50 } 51 func (m TestClientBuilder) DiscoveryClientOrDie(name string) discovery.DiscoveryInterface { 52 ret, err := m.DiscoveryClient(name) 53 if err != nil { 54 panic(err) 55 } 56 return ret 57 } 58 59 // FakeDiscoveryWithError inherits DiscoveryInterface(via FakeDiscovery) with some methods accepting testing data. 60 type FakeDiscoveryWithError struct { 61 fakediscovery.FakeDiscovery 62 PossibleResources []*metav1.APIResourceList 63 Err error 64 } 65 66 func (d FakeDiscoveryWithError) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) { 67 return d.PossibleResources, d.Err 68 } 69 70 // FakeDiscoveryWithError inherits Clientset(via FakeClientset) with overridden Discovery method. 71 type FakeClientSet struct { 72 fakeclientset.Clientset 73 DiscoveryObj *FakeDiscoveryWithError 74 } 75 76 func (c *FakeClientSet) Discovery() discovery.DiscoveryInterface { 77 return c.DiscoveryObj 78 } 79 80 func (c *FakeClientSet) GetPossibleResources() []*metav1.APIResourceList { 81 return c.DiscoveryObj.PossibleResources 82 } 83 84 // Create a fake Clientset with its Discovery method overridden. 85 func NewFakeClientset(fakeDiscovery FakeDiscoveryWithError) *FakeClientSet { 86 cs := &FakeClientSet{} 87 cs.DiscoveryObj = &fakeDiscovery 88 return cs 89 } 90 91 func possibleDiscoveryResource() []*metav1.APIResourceList { 92 return []*metav1.APIResourceList{ 93 { 94 GroupVersion: "create/v1", 95 APIResources: []metav1.APIResource{ 96 { 97 Name: "jobs", 98 Verbs: []string{"create", "list", "watch", "delete"}, 99 ShortNames: []string{"jz"}, 100 Categories: []string{"all"}, 101 }, 102 }, 103 }, 104 } 105 } 106 107 func TestController_DiscoveryError(t *testing.T) { 108 controllerDescriptorMap := map[string]*ControllerDescriptor{ 109 "ResourceQuotaController": newResourceQuotaControllerDescriptor(), 110 "GarbageCollectorController": newGarbageCollectorControllerDescriptor(), 111 "EndpointSliceController": newEndpointSliceControllerDescriptor(), 112 "EndpointSliceMirroringController": newEndpointSliceMirroringControllerDescriptor(), 113 "PodDisruptionBudgetController": newDisruptionControllerDescriptor(), 114 } 115 116 tcs := map[string]struct { 117 discoveryError error 118 expectedErr bool 119 possibleResources []*metav1.APIResourceList 120 }{ 121 "No Discovery Error": { 122 discoveryError: nil, 123 possibleResources: possibleDiscoveryResource(), 124 expectedErr: false, 125 }, 126 "Discovery Calls Partially Failed": { 127 discoveryError: new(discovery.ErrGroupDiscoveryFailed), 128 possibleResources: possibleDiscoveryResource(), 129 expectedErr: false, 130 }, 131 } 132 for name, test := range tcs { 133 testDiscovery := FakeDiscoveryWithError{Err: test.discoveryError, PossibleResources: test.possibleResources} 134 testClientset := NewFakeClientset(testDiscovery) 135 testClientBuilder := TestClientBuilder{clientset: testClientset} 136 testInformerFactory := informers.NewSharedInformerFactoryWithOptions(testClientset, time.Duration(1)) 137 ctx := ControllerContext{ 138 ClientBuilder: testClientBuilder, 139 InformerFactory: testInformerFactory, 140 ObjectOrMetadataInformerFactory: testInformerFactory, 141 InformersStarted: make(chan struct{}), 142 } 143 for controllerName, controllerDesc := range controllerDescriptorMap { 144 _, _, err := controllerDesc.GetInitFunc()(context.TODO(), ctx, controllerName) 145 if test.expectedErr != (err != nil) { 146 t.Errorf("%v test failed for use case: %v", controllerName, name) 147 } 148 } 149 _, _, err := startModifiedNamespaceController( 150 context.TODO(), ctx, testClientset, testClientBuilder.ConfigOrDie("namespace-controller")) 151 if test.expectedErr != (err != nil) { 152 t.Errorf("Namespace Controller test failed for use case: %v", name) 153 } 154 } 155 }