k8s.io/kubernetes@v1.29.3/pkg/controller/serviceaccount/serviceaccounts_controller_test.go (about) 1 /* 2 Copyright 2014 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 serviceaccount 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/sets" 27 "k8s.io/client-go/informers" 28 "k8s.io/client-go/kubernetes/fake" 29 core "k8s.io/client-go/testing" 30 "k8s.io/kubernetes/pkg/controller" 31 ) 32 33 func TestServiceAccountCreation(t *testing.T) { 34 ns := metav1.NamespaceDefault 35 36 defaultName := "default" 37 managedName := "managed" 38 39 activeNS := &v1.Namespace{ 40 ObjectMeta: metav1.ObjectMeta{Name: ns}, 41 Status: v1.NamespaceStatus{ 42 Phase: v1.NamespaceActive, 43 }, 44 } 45 terminatingNS := &v1.Namespace{ 46 ObjectMeta: metav1.ObjectMeta{Name: ns}, 47 Status: v1.NamespaceStatus{ 48 Phase: v1.NamespaceTerminating, 49 }, 50 } 51 defaultServiceAccount := &v1.ServiceAccount{ 52 ObjectMeta: metav1.ObjectMeta{ 53 Name: defaultName, 54 Namespace: ns, 55 ResourceVersion: "1", 56 }, 57 } 58 managedServiceAccount := &v1.ServiceAccount{ 59 ObjectMeta: metav1.ObjectMeta{ 60 Name: managedName, 61 Namespace: ns, 62 ResourceVersion: "1", 63 }, 64 } 65 unmanagedServiceAccount := &v1.ServiceAccount{ 66 ObjectMeta: metav1.ObjectMeta{ 67 Name: "other-unmanaged", 68 Namespace: ns, 69 ResourceVersion: "1", 70 }, 71 } 72 73 testcases := map[string]struct { 74 ExistingNamespace *v1.Namespace 75 ExistingServiceAccounts []*v1.ServiceAccount 76 77 AddedNamespace *v1.Namespace 78 UpdatedNamespace *v1.Namespace 79 DeletedServiceAccount *v1.ServiceAccount 80 81 ExpectCreatedServiceAccounts []string 82 }{ 83 "new active namespace missing serviceaccounts": { 84 ExistingServiceAccounts: []*v1.ServiceAccount{}, 85 AddedNamespace: activeNS, 86 ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(), 87 }, 88 "new active namespace missing serviceaccount": { 89 ExistingServiceAccounts: []*v1.ServiceAccount{managedServiceAccount}, 90 AddedNamespace: activeNS, 91 ExpectCreatedServiceAccounts: []string{defaultName}, 92 }, 93 "new active namespace with serviceaccounts": { 94 ExistingServiceAccounts: []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount}, 95 AddedNamespace: activeNS, 96 ExpectCreatedServiceAccounts: []string{}, 97 }, 98 99 "new terminating namespace": { 100 ExistingServiceAccounts: []*v1.ServiceAccount{}, 101 AddedNamespace: terminatingNS, 102 ExpectCreatedServiceAccounts: []string{}, 103 }, 104 105 "updated active namespace missing serviceaccounts": { 106 ExistingServiceAccounts: []*v1.ServiceAccount{}, 107 UpdatedNamespace: activeNS, 108 ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(), 109 }, 110 "updated active namespace missing serviceaccount": { 111 ExistingServiceAccounts: []*v1.ServiceAccount{defaultServiceAccount}, 112 UpdatedNamespace: activeNS, 113 ExpectCreatedServiceAccounts: []string{managedName}, 114 }, 115 "updated active namespace with serviceaccounts": { 116 ExistingServiceAccounts: []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount}, 117 UpdatedNamespace: activeNS, 118 ExpectCreatedServiceAccounts: []string{}, 119 }, 120 "updated terminating namespace": { 121 ExistingServiceAccounts: []*v1.ServiceAccount{}, 122 UpdatedNamespace: terminatingNS, 123 ExpectCreatedServiceAccounts: []string{}, 124 }, 125 126 "deleted serviceaccount without namespace": { 127 DeletedServiceAccount: defaultServiceAccount, 128 ExpectCreatedServiceAccounts: []string{}, 129 }, 130 "deleted serviceaccount with active namespace": { 131 ExistingServiceAccounts: []*v1.ServiceAccount{managedServiceAccount}, 132 ExistingNamespace: activeNS, 133 DeletedServiceAccount: defaultServiceAccount, 134 ExpectCreatedServiceAccounts: []string{defaultName}, 135 }, 136 "deleted serviceaccount with terminating namespace": { 137 ExistingNamespace: terminatingNS, 138 DeletedServiceAccount: defaultServiceAccount, 139 ExpectCreatedServiceAccounts: []string{}, 140 }, 141 "deleted unmanaged serviceaccount with active namespace": { 142 ExistingServiceAccounts: []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount}, 143 ExistingNamespace: activeNS, 144 DeletedServiceAccount: unmanagedServiceAccount, 145 ExpectCreatedServiceAccounts: []string{}, 146 }, 147 "deleted unmanaged serviceaccount with terminating namespace": { 148 ExistingNamespace: terminatingNS, 149 DeletedServiceAccount: unmanagedServiceAccount, 150 ExpectCreatedServiceAccounts: []string{}, 151 }, 152 } 153 154 for k, tc := range testcases { 155 client := fake.NewSimpleClientset(defaultServiceAccount, managedServiceAccount) 156 informers := informers.NewSharedInformerFactory(fake.NewSimpleClientset(), controller.NoResyncPeriodFunc()) 157 options := DefaultServiceAccountsControllerOptions() 158 options.ServiceAccounts = []v1.ServiceAccount{ 159 {ObjectMeta: metav1.ObjectMeta{Name: defaultName}}, 160 {ObjectMeta: metav1.ObjectMeta{Name: managedName}}, 161 } 162 saInformer := informers.Core().V1().ServiceAccounts() 163 nsInformer := informers.Core().V1().Namespaces() 164 controller, err := NewServiceAccountsController( 165 saInformer, 166 nsInformer, 167 client, 168 options, 169 ) 170 if err != nil { 171 t.Fatalf("error creating ServiceAccounts controller: %v", err) 172 } 173 controller.saListerSynced = alwaysReady 174 controller.nsListerSynced = alwaysReady 175 176 saStore := saInformer.Informer().GetStore() 177 nsStore := nsInformer.Informer().GetStore() 178 179 syncCalls := make(chan struct{}, 1) 180 controller.syncHandler = func(ctx context.Context, key string) error { 181 err := controller.syncNamespace(ctx, key) 182 if err != nil { 183 t.Logf("%s: %v", k, err) 184 } 185 186 syncCalls <- struct{}{} 187 return err 188 } 189 stopCh := make(chan struct{}) 190 defer close(stopCh) 191 go controller.Run(context.TODO(), 1) 192 193 if tc.ExistingNamespace != nil { 194 nsStore.Add(tc.ExistingNamespace) 195 } 196 for _, s := range tc.ExistingServiceAccounts { 197 saStore.Add(s) 198 } 199 200 if tc.AddedNamespace != nil { 201 nsStore.Add(tc.AddedNamespace) 202 controller.namespaceAdded(tc.AddedNamespace) 203 } 204 if tc.UpdatedNamespace != nil { 205 nsStore.Add(tc.UpdatedNamespace) 206 controller.namespaceUpdated(nil, tc.UpdatedNamespace) 207 } 208 if tc.DeletedServiceAccount != nil { 209 controller.serviceAccountDeleted(tc.DeletedServiceAccount) 210 } 211 212 // wait to be called 213 select { 214 case <-syncCalls: 215 case <-time.After(10 * time.Second): 216 t.Errorf("%s: took too long", k) 217 } 218 219 actions := client.Actions() 220 if len(tc.ExpectCreatedServiceAccounts) != len(actions) { 221 t.Errorf("%s: Expected to create accounts %#v. Actual actions were: %#v", k, tc.ExpectCreatedServiceAccounts, actions) 222 continue 223 } 224 for i, expectedName := range tc.ExpectCreatedServiceAccounts { 225 action := actions[i] 226 if !action.Matches("create", "serviceaccounts") { 227 t.Errorf("%s: Unexpected action %s", k, action) 228 break 229 } 230 createdAccount := action.(core.CreateAction).GetObject().(*v1.ServiceAccount) 231 if createdAccount.Name != expectedName { 232 t.Errorf("%s: Expected %s to be created, got %s", k, expectedName, createdAccount.Name) 233 } 234 } 235 } 236 } 237 238 var alwaysReady = func() bool { return true }