github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/caasrbacmapper/mapper_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasrbacmapper_test 5 6 import ( 7 "sync" 8 "testing" 9 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 jc "github.com/juju/testing/checkers" 13 "go.uber.org/mock/gomock" 14 gc "gopkg.in/check.v1" 15 core "k8s.io/api/core/v1" 16 k8serrors "k8s.io/apimachinery/pkg/api/errors" 17 meta "k8s.io/apimachinery/pkg/apis/meta/v1" 18 "k8s.io/apimachinery/pkg/types" 19 "k8s.io/client-go/tools/cache" 20 21 "github.com/juju/juju/caas/kubernetes/provider" 22 "github.com/juju/juju/caas/kubernetes/provider/mocks" 23 coretesting "github.com/juju/juju/testing" 24 "github.com/juju/juju/worker/caasrbacmapper" 25 ) 26 27 type MapperSuite struct { 28 ctrl *gomock.Controller 29 mockSAInformer *mocks.MockServiceAccountInformer 30 mockSALister *mocks.MockServiceAccountLister 31 mockSANamespaceLister *mocks.MockServiceAccountNamespaceLister 32 mockSharedIndexInformer *mocks.MockSharedIndexInformer 33 } 34 35 var _ = gc.Suite(&MapperSuite{}) 36 37 func TestMapperSuite(t *testing.T) { gc.TestingT(t) } 38 39 func (m *MapperSuite) SetUpTest(c *gc.C) { 40 m.ctrl = gomock.NewController(c) 41 m.mockSAInformer = mocks.NewMockServiceAccountInformer(m.ctrl) 42 m.mockSharedIndexInformer = mocks.NewMockSharedIndexInformer(m.ctrl) 43 m.mockSharedIndexInformer.EXPECT().HasSynced().AnyTimes().Return(true) 44 m.mockSALister = mocks.NewMockServiceAccountLister(m.ctrl) 45 m.mockSANamespaceLister = mocks.NewMockServiceAccountNamespaceLister(m.ctrl) 46 m.mockSharedIndexInformer.EXPECT().Run(gomock.Any()).AnyTimes() 47 m.mockSAInformer.EXPECT().Informer().AnyTimes().Return(m.mockSharedIndexInformer) 48 m.mockSAInformer.EXPECT().Lister().AnyTimes().Return(m.mockSALister) 49 } 50 51 func (m *MapperSuite) TestMapperAdditionSync(c *gc.C) { 52 defer m.ctrl.Finish() 53 waitGroup := sync.WaitGroup{} 54 waitGroup.Add(1) 55 var eventHandlers cache.ResourceEventHandlerFuncs 56 m.mockSharedIndexInformer.EXPECT().AddEventHandler(gomock.Any()). 57 DoAndReturn(func(h cache.ResourceEventHandlerFuncs) { 58 eventHandlers = h 59 waitGroup.Done() 60 }).Return(m.mockSharedIndexInformer, nil) 61 62 mapper, err := caasrbacmapper.NewMapper(loggo.Logger{}, m.mockSAInformer) 63 c.Assert(err, jc.ErrorIsNil) 64 waitGroup.Wait() 65 66 appName := "test" 67 name := "test-sa" 68 namespace := "test-model" 69 uid := types.UID("123") 70 sa := &core.ServiceAccount{ 71 ObjectMeta: meta.ObjectMeta{ 72 Name: name, 73 Namespace: namespace, 74 Labels: provider.RBACLabels(appName, "test-model", false, false), 75 UID: uid, 76 }, 77 } 78 79 waitGroup.Add(1) 80 m.mockSALister.EXPECT().ServiceAccounts(gomock.Eq(namespace)). 81 Return(m.mockSANamespaceLister) 82 m.mockSANamespaceLister.EXPECT().Get(gomock.Eq(name)). 83 DoAndReturn(func(_ string) (*core.ServiceAccount, error) { 84 waitGroup.Done() 85 return sa, nil 86 }) 87 88 eventHandlers.OnAdd(sa, false) 89 waitGroup.Wait() 90 91 mapper.Kill() 92 mapper.Wait() 93 94 for a := coretesting.LongAttempt.Start(); a.Next(); { 95 rAppName, err := mapper.AppNameForServiceAccount(uid) 96 if err == nil { 97 c.Assert(rAppName, gc.Equals, appName) 98 break 99 } 100 if !a.HasNext() { 101 c.Fatal("timed out waiting for service account app") 102 } 103 } 104 } 105 106 func (m *MapperSuite) TestRBACMapperUpdateSync(c *gc.C) { 107 defer m.ctrl.Finish() 108 waitGroup := sync.WaitGroup{} 109 waitGroup.Add(1) 110 var eventHandlers cache.ResourceEventHandlerFuncs 111 m.mockSharedIndexInformer.EXPECT().AddEventHandler(gomock.Any()). 112 DoAndReturn(func(h cache.ResourceEventHandlerFuncs) { 113 eventHandlers = h 114 waitGroup.Done() 115 }).Return(m.mockSharedIndexInformer, nil) 116 117 mapper, err := caasrbacmapper.NewMapper(loggo.Logger{}, m.mockSAInformer) 118 c.Assert(err, jc.ErrorIsNil) 119 waitGroup.Wait() 120 121 appName := "test" 122 name := "test-sa" 123 namespace := "test-model" 124 uid := types.UID("123") 125 sa := &core.ServiceAccount{ 126 ObjectMeta: meta.ObjectMeta{ 127 Name: name, 128 Namespace: namespace, 129 Labels: provider.RBACLabels(appName, "test-model", false, false), 130 UID: uid, 131 }, 132 } 133 134 waitGroup.Add(1) 135 m.mockSALister.EXPECT().ServiceAccounts(gomock.Eq(namespace)). 136 Return(m.mockSANamespaceLister).AnyTimes() 137 m.mockSANamespaceLister.EXPECT().Get(gomock.Eq(name)). 138 DoAndReturn(func(_ string) (*core.ServiceAccount, error) { 139 waitGroup.Done() 140 return sa, nil 141 }) 142 143 eventHandlers.OnAdd(sa, false) 144 waitGroup.Wait() 145 146 for a := coretesting.LongAttempt.Start(); a.Next(); { 147 rAppName, err := mapper.AppNameForServiceAccount(uid) 148 if err == nil { 149 c.Assert(rAppName, gc.Equals, appName) 150 break 151 } 152 if !a.HasNext() { 153 c.Fatal("timed out waiting for service account app") 154 } 155 } 156 157 // Update SA with a new app name to check propagation 158 appName = "test-2" 159 sa2 := sa.DeepCopy() 160 sa2.ObjectMeta.Labels = provider.RBACLabels(appName, "test-model", false, false) 161 waitGroup.Add(1) 162 m.mockSANamespaceLister.EXPECT().Get(gomock.Eq(name)). 163 DoAndReturn(func(_ string) (*core.ServiceAccount, error) { 164 waitGroup.Done() 165 return sa2, nil 166 }) 167 168 //Send the update event, oldObj, newObj 169 eventHandlers.OnUpdate(sa, sa2) 170 waitGroup.Wait() 171 172 mapper.Kill() 173 mapper.Wait() 174 175 for a := coretesting.LongAttempt.Start(); a.Next(); { 176 rAppName, err := mapper.AppNameForServiceAccount(uid) 177 if err == nil { 178 c.Assert(rAppName, gc.Equals, appName) 179 break 180 } 181 if !a.HasNext() { 182 c.Fatal("timed out waiting for service account app") 183 } 184 } 185 } 186 187 func (m *MapperSuite) TestRBACMapperDeleteSync(c *gc.C) { 188 defer m.ctrl.Finish() 189 waitGroup := sync.WaitGroup{} 190 waitGroup.Add(1) 191 var eventHandlers cache.ResourceEventHandlerFuncs 192 m.mockSharedIndexInformer.EXPECT().AddEventHandler(gomock.Any()). 193 DoAndReturn(func(h cache.ResourceEventHandlerFuncs) { 194 eventHandlers = h 195 waitGroup.Done() 196 }).Return(m.mockSharedIndexInformer, nil) 197 198 mapper, err := caasrbacmapper.NewMapper(loggo.Logger{}, m.mockSAInformer) 199 c.Assert(err, jc.ErrorIsNil) 200 waitGroup.Wait() 201 202 appName := "test" 203 name := "test-sa" 204 namespace := "test-model" 205 uid := types.UID("123") 206 sa := &core.ServiceAccount{ 207 ObjectMeta: meta.ObjectMeta{ 208 Name: name, 209 Namespace: namespace, 210 Labels: provider.RBACLabels(appName, "test-model", false, false), 211 UID: uid, 212 }, 213 } 214 215 m.mockSALister.EXPECT().ServiceAccounts(gomock.Eq(namespace)). 216 Return(m.mockSANamespaceLister).AnyTimes() 217 m.mockSANamespaceLister.EXPECT().Get(gomock.Eq(name)).Return(sa, nil) 218 eventHandlers.OnAdd(sa, false) 219 220 for a := coretesting.LongAttempt.Start(); a.Next(); { 221 rAppName, err := mapper.AppNameForServiceAccount(uid) 222 if err == nil { 223 c.Assert(rAppName, gc.Equals, appName) 224 break 225 } 226 if !a.HasNext() { 227 c.Fatal("timed out waiting for service account app") 228 } 229 } 230 231 // Update SA with a new app name to check propagation 232 m.mockSANamespaceLister.EXPECT().Get(gomock.Eq(name)).Return( 233 nil, k8serrors.NewNotFound(core.Resource("serviceaccount"), name)) 234 235 //Send the delete event for the service account 236 eventHandlers.OnDelete(sa) 237 238 mapper.Kill() 239 mapper.Wait() 240 241 for a := coretesting.LongAttempt.Start(); a.Next(); { 242 _, err = mapper.AppNameForServiceAccount(uid) 243 if err != nil { 244 c.Assert(errors.IsNotFound(err), jc.IsTrue) 245 break 246 } 247 if !a.HasNext() { 248 c.Fatal("timed out waiting for service account app to be removed") 249 } 250 } 251 } 252 253 func (m *MapperSuite) TestRBACMapperNotFound(c *gc.C) { 254 defer m.ctrl.Finish() 255 m.mockSharedIndexInformer.EXPECT().AddEventHandler(gomock.Any()) 256 257 mapper, err := caasrbacmapper.NewMapper(loggo.Logger{}, m.mockSAInformer) 258 c.Assert(err, jc.ErrorIsNil) 259 260 _, err = mapper.AppNameForServiceAccount("testing") 261 c.Assert(errors.IsNotFound(err), jc.IsTrue) 262 }