github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/clusters/multiclustercomponent/controller_test.go (about)

     1  // Copyright (c) 2021, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package multiclustercomponent
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/go-logr/logr"
    13  	"github.com/verrazzano/verrazzano/application-operator/constants"
    14  	vzconst "github.com/verrazzano/verrazzano/pkg/constants"
    15  
    16  	"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
    17  	"github.com/golang/mock/gomock"
    18  	asserts "github.com/stretchr/testify/assert"
    19  	clustersv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1"
    20  	"github.com/verrazzano/verrazzano/application-operator/controllers/clusters"
    21  	clusterstest "github.com/verrazzano/verrazzano/application-operator/controllers/clusters/test"
    22  	"github.com/verrazzano/verrazzano/application-operator/mocks"
    23  	"go.uber.org/zap"
    24  	v1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"k8s.io/apimachinery/pkg/types"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  )
    32  
    33  const namespace = "unit-mccomp-namespace"
    34  const crName = "unit-mccomp"
    35  
    36  // TestComponentReconcilerSetupWithManager test the creation of the MultiClusterComponentReconciler.
    37  // GIVEN a controller implementation
    38  // WHEN the controller is created
    39  // THEN verify no error is returned
    40  func TestComponentReconcilerSetupWithManager(t *testing.T) {
    41  	assert := asserts.New(t)
    42  
    43  	var mocker *gomock.Controller
    44  	var mgr *mocks.MockManager
    45  	var cli *mocks.MockClient
    46  	var scheme *runtime.Scheme
    47  	var reconciler Reconciler
    48  	var err error
    49  
    50  	mocker = gomock.NewController(t)
    51  	mgr = mocks.NewMockManager(mocker)
    52  	cli = mocks.NewMockClient(mocker)
    53  	scheme = runtime.NewScheme()
    54  	_ = clustersv1alpha1.AddToScheme(scheme)
    55  	reconciler = Reconciler{Client: cli, Scheme: scheme}
    56  	mgr.EXPECT().GetControllerOptions().AnyTimes()
    57  	mgr.EXPECT().GetScheme().Return(scheme)
    58  	mgr.EXPECT().GetLogger().Return(logr.Discard())
    59  	mgr.EXPECT().SetFields(gomock.Any()).Return(nil).AnyTimes()
    60  	mgr.EXPECT().Add(gomock.Any()).Return(nil).AnyTimes()
    61  	err = reconciler.SetupWithManager(mgr)
    62  	mocker.Finish()
    63  	assert.NoError(err)
    64  }
    65  
    66  // TestReconcileCreateComponent tests the basic happy path of reconciling a MultiClusterComponent. We
    67  // expect to write out an OAM component
    68  // GIVEN a MultiClusterComponent resource is created
    69  // WHEN the controller Reconcile function is called
    70  // THEN expect an OAM component to be created
    71  func TestReconcileCreateComponent(t *testing.T) {
    72  	assert := asserts.New(t)
    73  
    74  	mocker := gomock.NewController(t)
    75  	cli := mocks.NewMockClient(mocker)
    76  	mockStatusWriter := mocks.NewMockStatusWriter(mocker)
    77  
    78  	mcCompSample, err := getSampleMCComponent()
    79  
    80  	if err != nil {
    81  		t.Fatalf(err.Error())
    82  	}
    83  
    84  	// expect a call to fetch the MultiClusterComponent
    85  	doExpectGetMultiClusterComponent(cli, mcCompSample, false)
    86  
    87  	// expect a call to fetch the MCRegistration secret
    88  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
    89  
    90  	// expect a call to fetch existing OAM component, and return not found error, to test create case
    91  	cli.EXPECT().
    92  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: crName}, gomock.Not(gomock.Nil()), gomock.Any()).
    93  		Return(errors.NewNotFound(schema.GroupResource{Group: "core.oam.dev", Resource: "Component"}, crName))
    94  
    95  	// expect a call to create the OAM component
    96  	cli.EXPECT().
    97  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
    98  		DoAndReturn(func(ctx context.Context, c *v1alpha2.Component, opts ...client.CreateOption) error {
    99  			assertComponentValid(assert, c, mcCompSample)
   100  			return nil
   101  		})
   102  
   103  	// expect a call to update the resource with a finalizer
   104  	cli.EXPECT().
   105  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   106  		DoAndReturn(func(ctx context.Context, component *clustersv1alpha1.MultiClusterComponent, opts ...client.UpdateOption) error {
   107  			assert.True(len(component.ObjectMeta.Finalizers) == 1, "Wrong number of finalizers")
   108  			assert.Equal(finalizerName, component.ObjectMeta.Finalizers[0], "wrong finalizer")
   109  			return nil
   110  		})
   111  
   112  	// expect a call to update the status of the MultiClusterComponent
   113  	doExpectStatusUpdateSucceeded(cli, mockStatusWriter, assert)
   114  
   115  	// create a request and reconcile it
   116  	request := clusterstest.NewRequest(namespace, crName)
   117  	reconciler := newReconciler(cli)
   118  	result, err := reconciler.Reconcile(context.TODO(), request)
   119  
   120  	mocker.Finish()
   121  	assert.NoError(err)
   122  	assert.Equal(false, result.Requeue)
   123  }
   124  
   125  // TestReconcileUpdateComponent tests the path of reconciling a MultiClusterComponent when the
   126  // underlying OAM component already exists i.e. update case
   127  // GIVEN a MultiClusterComponent resource is created
   128  // WHEN the controller Reconcile function is called
   129  // THEN expect an OAM component to be updated
   130  func TestReconcileUpdateComponent(t *testing.T) {
   131  	assert := asserts.New(t)
   132  
   133  	mocker := gomock.NewController(t)
   134  	cli := mocks.NewMockClient(mocker)
   135  	mockStatusWriter := mocks.NewMockStatusWriter(mocker)
   136  
   137  	mcCompSample, err := getSampleMCComponent()
   138  	if err != nil {
   139  		t.Fatalf(err.Error())
   140  	}
   141  
   142  	existingOAMComp, err := getExistingOAMComponent()
   143  	if err != nil {
   144  		t.Fatalf(err.Error())
   145  	}
   146  
   147  	// expect a call to fetch the MultiClusterComponent
   148  	doExpectGetMultiClusterComponent(cli, mcCompSample, true)
   149  
   150  	// expect a call to fetch the MCRegistration secret
   151  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   152  
   153  	// expect a call to fetch underlying OAM component, and return an existing component
   154  	doExpectGetComponentExists(cli, mcCompSample.ObjectMeta, existingOAMComp.Spec)
   155  
   156  	// expect a call to update the OAM component with the new component workload data
   157  	cli.EXPECT().
   158  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   159  		DoAndReturn(func(ctx context.Context, c *v1alpha2.Component, opts ...client.CreateOption) error {
   160  			assertComponentValid(assert, c, mcCompSample)
   161  			return nil
   162  		})
   163  
   164  	// expect a call to update the status of the multicluster component
   165  	doExpectStatusUpdateSucceeded(cli, mockStatusWriter, assert)
   166  
   167  	// create a request and reconcile it
   168  	request := clusterstest.NewRequest(namespace, crName)
   169  	reconciler := newReconciler(cli)
   170  	result, err := reconciler.Reconcile(context.TODO(), request)
   171  
   172  	mocker.Finish()
   173  	assert.NoError(err)
   174  	assert.Equal(false, result.Requeue)
   175  }
   176  
   177  // TestReconcileCreateComponentFailed tests the path of reconciling a MultiClusterComponent
   178  // when the underlying OAM component does not exist and fails to be created due to some error condition
   179  // GIVEN a MultiClusterComponent resource is created
   180  // WHEN the controller Reconcile function is called and create underlying component fails
   181  // THEN expect the status of the MultiClusterComponent to be updated with failure information
   182  func TestReconcileCreateComponentFailed(t *testing.T) {
   183  	assert := asserts.New(t)
   184  
   185  	mocker := gomock.NewController(t)
   186  	cli := mocks.NewMockClient(mocker)
   187  	mockStatusWriter := mocks.NewMockStatusWriter(mocker)
   188  
   189  	mcCompSample, err := getSampleMCComponent()
   190  	if err != nil {
   191  		t.Fatalf(err.Error())
   192  	}
   193  
   194  	// expect a call to fetch the MultiClusterComponent
   195  	doExpectGetMultiClusterComponent(cli, mcCompSample, false)
   196  
   197  	// expect a call to fetch the MCRegistration secret
   198  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   199  
   200  	// expect a call to fetch existing OAM component and return not found error, to simulate create case
   201  	cli.EXPECT().
   202  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: crName}, gomock.Not(gomock.Nil()), gomock.Any()).
   203  		Return(errors.NewNotFound(schema.GroupResource{Group: "core.oam.dev", Resource: "Component"}, crName))
   204  
   205  	// expect a call to create the OAM component and fail the call
   206  	cli.EXPECT().
   207  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
   208  		DoAndReturn(func(ctx context.Context, c *v1alpha2.Component, opts ...client.CreateOption) error {
   209  			return errors.NewBadRequest("will not create it")
   210  		})
   211  
   212  	// expect that the status of MultiClusterComponent is updated to failed because we
   213  	// failed the underlying OAM component's creation
   214  	doExpectStatusUpdateFailed(cli, mockStatusWriter, assert)
   215  
   216  	// create a request and reconcile it
   217  	request := clusterstest.NewRequest(namespace, crName)
   218  	reconciler := newReconciler(cli)
   219  	result, err := reconciler.Reconcile(context.TODO(), request)
   220  
   221  	mocker.Finish()
   222  	assert.Nil(err)
   223  	assert.Equal(true, result.Requeue)
   224  }
   225  
   226  // TestReconcileCreateComponentFailed tests the path of reconciling a MultiClusterComponent
   227  // when the underlying OAM component exists and fails to be updated due to some error condition
   228  // GIVEN a MultiClusterComponent resource is created
   229  // WHEN the controller Reconcile function is called and update underlying component fails
   230  // THEN expect the status of the MultiClusterComponent to be updated with failure information
   231  func TestReconcileUpdateComponentFailed(t *testing.T) {
   232  	assert := asserts.New(t)
   233  
   234  	mocker := gomock.NewController(t)
   235  	cli := mocks.NewMockClient(mocker)
   236  	mockStatusWriter := mocks.NewMockStatusWriter(mocker)
   237  
   238  	mcCompSample, err := getSampleMCComponent()
   239  	if err != nil {
   240  		t.Fatalf(err.Error())
   241  	}
   242  
   243  	existingOAMComp, err := getExistingOAMComponent()
   244  	if err != nil {
   245  		t.Fatalf(err.Error())
   246  	}
   247  
   248  	// expect a call to fetch the MultiClusterComponent
   249  	doExpectGetMultiClusterComponent(cli, mcCompSample, true)
   250  
   251  	// expect a call to fetch the MCRegistration secret
   252  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   253  
   254  	// expect a call to fetch existing OAM component (simulate update case)
   255  	doExpectGetComponentExists(cli, mcCompSample.ObjectMeta, existingOAMComp.Spec)
   256  
   257  	// expect a call to update the OAM component and fail the call
   258  	cli.EXPECT().
   259  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   260  		DoAndReturn(func(ctx context.Context, c *v1alpha2.Component, opts ...client.UpdateOption) error {
   261  			return errors.NewBadRequest("will not update it")
   262  		})
   263  
   264  	// expect that the status of MultiClusterComponent is updated to failed because we
   265  	// failed the underlying OAM component's creation
   266  	doExpectStatusUpdateFailed(cli, mockStatusWriter, assert)
   267  
   268  	// create a request and reconcile it
   269  	request := clusterstest.NewRequest(namespace, crName)
   270  	reconciler := newReconciler(cli)
   271  	result, err := reconciler.Reconcile(context.TODO(), request)
   272  
   273  	mocker.Finish()
   274  	assert.Nil(err)
   275  	assert.Equal(true, result.Requeue)
   276  }
   277  
   278  // TestReconcilePlacementInDifferentCluster tests the path of reconciling a MultiClusterComponent which
   279  // is placed on a cluster other than the current cluster. We expect this MultiClusterComponent to
   280  // be ignored, and no OAM Component to be created
   281  // GIVEN a MultiClusterComponent resource is created with a placement in different cluster
   282  // WHEN the controller Reconcile function is called
   283  // THEN expect that no OAM Component is created
   284  func TestReconcilePlacementInDifferentCluster(t *testing.T) {
   285  	assert := asserts.New(t)
   286  
   287  	mocker := gomock.NewController(t)
   288  	cli := mocks.NewMockClient(mocker)
   289  	statusWriter := mocks.NewMockStatusWriter(mocker)
   290  
   291  	mcCompSample, err := getSampleMCComponent()
   292  	if err != nil {
   293  		t.Fatalf(err.Error())
   294  	}
   295  
   296  	mcCompSample.Spec.Placement.Clusters[0].Name = "not-my-cluster"
   297  
   298  	// expect a call to fetch the MultiClusterComponent
   299  	doExpectGetMultiClusterComponent(cli, mcCompSample, true)
   300  
   301  	// expect a call to fetch the MCRegistration secret
   302  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   303  
   304  	// The effective state of the object will get updated even if it is note locally placed,
   305  	// since it would have changed
   306  	clusterstest.DoExpectUpdateState(t, cli, statusWriter, &mcCompSample, clustersv1alpha1.Pending)
   307  
   308  	clusterstest.ExpectDeleteAssociatedResource(cli, &v1alpha2.Component{
   309  		ObjectMeta: metav1.ObjectMeta{
   310  			Name:      mcCompSample.Name,
   311  			Namespace: mcCompSample.Namespace,
   312  		},
   313  	}, types.NamespacedName{
   314  		Namespace: mcCompSample.Namespace,
   315  		Name:      mcCompSample.Name,
   316  	})
   317  
   318  	// expect a call to update the resource with no finalizers
   319  	cli.EXPECT().
   320  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   321  		DoAndReturn(func(ctx context.Context, mcComponent *clustersv1alpha1.MultiClusterComponent, opts ...client.UpdateOption) error {
   322  			assert.True(len(mcComponent.Finalizers) == 0, "Wrong number of finalizers")
   323  			return nil
   324  		})
   325  
   326  	// Expect no further action
   327  
   328  	// create a request and reconcile it
   329  	request := clusterstest.NewRequest(namespace, crName)
   330  	reconciler := newReconciler(cli)
   331  	result, err := reconciler.Reconcile(context.TODO(), request)
   332  
   333  	mocker.Finish()
   334  	assert.NoError(err)
   335  	assert.Equal(false, result.Requeue)
   336  }
   337  
   338  // TestReconcileResourceNotFound tests the path of reconciling a
   339  // MultiClusterComponent resource which is non-existent when reconcile is called,
   340  // possibly because it has been deleted.
   341  // GIVEN a MultiClusterComponent resource has been deleted
   342  // WHEN the controller Reconcile function is called
   343  // THEN expect that no action is taken
   344  func TestReconcileResourceNotFound(t *testing.T) {
   345  	assert := asserts.New(t)
   346  
   347  	mocker := gomock.NewController(t)
   348  	cli := mocks.NewMockClient(mocker)
   349  
   350  	// expect a call to fetch the MultiClusterComponent
   351  	// and return a not found error
   352  	cli.EXPECT().
   353  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: crName}, gomock.Not(gomock.Nil()), gomock.Any()).
   354  		Return(errors.NewNotFound(schema.GroupResource{Group: clustersv1alpha1.SchemeGroupVersion.Group, Resource: clustersv1alpha1.MultiClusterComponentResource}, crName))
   355  
   356  	// expect no further action to be taken
   357  
   358  	// create a request and reconcile it
   359  	request := clusterstest.NewRequest(namespace, crName)
   360  	reconciler := newReconciler(cli)
   361  	result, err := reconciler.Reconcile(context.TODO(), request)
   362  
   363  	mocker.Finish()
   364  	assert.NoError(err)
   365  	assert.Equal(false, result.Requeue)
   366  }
   367  
   368  // doExpectGetComponentExists expects a call to get an OAM component and return an "existing" one
   369  func doExpectGetComponentExists(cli *mocks.MockClient, metadata metav1.ObjectMeta, componentSpec v1alpha2.ComponentSpec) {
   370  	cli.EXPECT().
   371  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: crName}, gomock.Not(gomock.Nil()), gomock.Any()).
   372  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, component *v1alpha2.Component, opts ...client.GetOption) error {
   373  			component.Spec = componentSpec
   374  			component.ObjectMeta = metadata
   375  			return nil
   376  		})
   377  }
   378  
   379  // doExpectStatusUpdateFailed expects a call to update status of MultiClusterComponent to failure
   380  func doExpectStatusUpdateFailed(cli *mocks.MockClient, mockStatusWriter *mocks.MockStatusWriter, assert *asserts.Assertions) {
   381  	// expect a call to fetch the MCRegistration secret to get the cluster name for status update
   382  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   383  
   384  	// expect a call to update the status of the MultiClusterComponent
   385  	cli.EXPECT().Status().Return(mockStatusWriter)
   386  
   387  	// the status update should be to failure status/conditions on the MultiClusterComponent
   388  	mockStatusWriter.EXPECT().
   389  		Update(gomock.Any(), gomock.AssignableToTypeOf(&clustersv1alpha1.MultiClusterComponent{}), gomock.Any()).
   390  		DoAndReturn(func(ctx context.Context, mcComp *clustersv1alpha1.MultiClusterComponent, opts ...client.UpdateOption) error {
   391  			clusterstest.AssertMultiClusterResourceStatus(assert, mcComp.Status,
   392  				clustersv1alpha1.Failed, clustersv1alpha1.DeployFailed, v1.ConditionTrue)
   393  			return nil
   394  		})
   395  }
   396  
   397  // doExpectStatusUpdateSucceeded expects a call to update status of MultiClusterComponent to success
   398  func doExpectStatusUpdateSucceeded(cli *mocks.MockClient, mockStatusWriter *mocks.MockStatusWriter, assert *asserts.Assertions) {
   399  	// expect a call to fetch the MCRegistration secret to get the cluster name for status update
   400  	clusterstest.DoExpectGetMCRegistrationSecret(cli)
   401  
   402  	// expect a call to update the status of the MultiClusterComponent
   403  	cli.EXPECT().Status().Return(mockStatusWriter)
   404  
   405  	// the status update should be to success status/conditions on the MultiClusterComponent
   406  	mockStatusWriter.EXPECT().
   407  		Update(gomock.Any(), gomock.AssignableToTypeOf(&clustersv1alpha1.MultiClusterComponent{}), gomock.Any()).
   408  		DoAndReturn(func(ctx context.Context, mcComp *clustersv1alpha1.MultiClusterComponent, opts ...client.UpdateOption) error {
   409  			clusterstest.AssertMultiClusterResourceStatus(assert, mcComp.Status,
   410  				clustersv1alpha1.Succeeded, clustersv1alpha1.DeployComplete, v1.ConditionTrue)
   411  			return nil
   412  		})
   413  }
   414  
   415  // doExpectGetMultiClusterComponent adds an expectation to the given MockClient to expect a Get
   416  // call for a MultiClusterComponent, and populate the multi cluster component with given data
   417  func doExpectGetMultiClusterComponent(cli *mocks.MockClient, mcCompSample clustersv1alpha1.MultiClusterComponent, addFinalizer bool) {
   418  	cli.EXPECT().
   419  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: crName}, gomock.AssignableToTypeOf(&mcCompSample), gomock.Any()).
   420  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, mcComp *clustersv1alpha1.MultiClusterComponent, opts ...client.GetOption) error {
   421  			mcComp.ObjectMeta = mcCompSample.ObjectMeta
   422  			mcComp.TypeMeta = mcCompSample.TypeMeta
   423  			mcComp.Spec = mcCompSample.Spec
   424  			if addFinalizer {
   425  				mcComp.Finalizers = append(mcComp.Finalizers, finalizerName)
   426  			}
   427  			return nil
   428  		})
   429  }
   430  
   431  // assertComponentValid asserts that the metadata and content of the created/updated OAM component
   432  // are valid
   433  func assertComponentValid(assert *asserts.Assertions, c *v1alpha2.Component, mcComp clustersv1alpha1.MultiClusterComponent) {
   434  	assert.Equal(namespace, c.ObjectMeta.Namespace)
   435  	assert.Equal(crName, c.ObjectMeta.Name)
   436  	assert.Equal(mcComp.Spec.Template.Spec, c.Spec)
   437  
   438  	// assert that the component is labeled verrazzano-managed=true since it was created by Verrazzano
   439  	assert.NotNil(c.Labels)
   440  	assert.Equal(constants.LabelVerrazzanoManagedDefault, c.Labels[vzconst.VerrazzanoManagedLabelKey])
   441  
   442  	// assert some fields on the component spec (e.g. in the case of update, these fields should
   443  	// be different from the mock pre existing OAM component)
   444  	expectedContainerizedWorkload, err := clusterstest.ReadContainerizedWorkload(mcComp.Spec.Template.Spec.Workload)
   445  	assert.Nil(err)
   446  	actualContainerizedWorkload, err := clusterstest.ReadContainerizedWorkload(c.Spec.Workload)
   447  	assert.Nil(err)
   448  	assert.Equal(expectedContainerizedWorkload.Spec.Containers[0].Name, actualContainerizedWorkload.Spec.Containers[0].Name)
   449  	assert.Equal(expectedContainerizedWorkload.Name, actualContainerizedWorkload.Name)
   450  
   451  }
   452  
   453  // getSampleMCComponent creates and returns a sample MultiClusterComponent used in tests
   454  func getSampleMCComponent() (clustersv1alpha1.MultiClusterComponent, error) {
   455  	mcComp := clustersv1alpha1.MultiClusterComponent{}
   456  	sampleComponentFile, err := filepath.Abs("testdata/hello-multiclustercomponent.yaml")
   457  	if err != nil {
   458  		return mcComp, err
   459  	}
   460  
   461  	rawMcComp, err := clusterstest.ReadYaml2Json(sampleComponentFile)
   462  	if err != nil {
   463  		return mcComp, err
   464  	}
   465  
   466  	err = json.Unmarshal(rawMcComp, &mcComp)
   467  	return mcComp, err
   468  }
   469  
   470  func getExistingOAMComponent() (v1alpha2.Component, error) {
   471  	oamComp := v1alpha2.Component{}
   472  	existingComponentFile, err := filepath.Abs("testdata/hello-oam-comp-existing.yaml")
   473  	if err != nil {
   474  		return oamComp, err
   475  	}
   476  	rawMcComp, err := clusterstest.ReadYaml2Json(existingComponentFile)
   477  	if err != nil {
   478  		return oamComp, err
   479  	}
   480  
   481  	err = json.Unmarshal(rawMcComp, &oamComp)
   482  	return oamComp, err
   483  }
   484  
   485  // newReconciler creates a new reconciler for testing
   486  // c - The K8s client to inject into the reconciler
   487  func newReconciler(c client.Client) Reconciler {
   488  	return Reconciler{
   489  		Client: c,
   490  		Log:    zap.S().With("test"),
   491  		Scheme: clusters.NewScheme(),
   492  	}
   493  }
   494  
   495  // TestReconcileKubeSystem tests to make sure we do not reconcile
   496  // Any resource that belong to the kube-system namespace
   497  func TestReconcileKubeSystem(t *testing.T) {
   498  	assert := asserts.New(t)
   499  
   500  	var mocker = gomock.NewController(t)
   501  	var cli = mocks.NewMockClient(mocker)
   502  
   503  	// create a request and reconcile it
   504  	request := clusterstest.NewRequest(vzconst.KubeSystem, "unit-test-verrazzano-helidon-workload")
   505  	reconciler := newReconciler(cli)
   506  	result, err := reconciler.Reconcile(context.TODO(), request)
   507  
   508  	mocker.Finish()
   509  	assert.Nil(err)
   510  	assert.True(result.IsZero())
   511  }