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  }