github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/navigation/workload_test.go (about)

     1  // Copyright (c) 2020, 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 navigation
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  	"testing"
    11  
    12  	vzapi "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    13  	"github.com/verrazzano/verrazzano/application-operator/mocks"
    14  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    15  
    16  	oamcore "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
    17  	"github.com/crossplane/oam-kubernetes-runtime/pkg/oam"
    18  	"github.com/golang/mock/gomock"
    19  	asserts "github.com/stretchr/testify/assert"
    20  	"go.uber.org/zap"
    21  	k8sapps "k8s.io/api/apps/v1"
    22  	"k8s.io/apimachinery/pkg/api/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  )
    29  
    30  const (
    31  	namespace = "test-namespace"
    32  )
    33  
    34  // TestFetchWorkloadDefinition tests the FetchWorkloadDefinition function
    35  func TestFetchWorkloadDefinition(t *testing.T) {
    36  	assert := asserts.New(t)
    37  
    38  	var mocker *gomock.Controller
    39  	var cli *mocks.MockClient
    40  	var ctx = context.TODO()
    41  	var err error
    42  	var workload unstructured.Unstructured
    43  	var definition *oamcore.WorkloadDefinition
    44  
    45  	// GIVEN a nil workload reference
    46  	// WHEN an attempt is made to fetch the workload definition
    47  	// THEN expect an error
    48  	mocker = gomock.NewController(t)
    49  	cli = mocks.NewMockClient(mocker)
    50  	definition, err = FetchWorkloadDefinition(ctx, cli, vzlog.DefaultLogger(), nil)
    51  	mocker.Finish()
    52  	assert.Error(err)
    53  	assert.Nil(definition)
    54  
    55  	// GIVEN a valid workload reference
    56  	// WHEN an attempt is made to fetch the workload definition
    57  	// THEN the workload definition to be returned
    58  	mocker = gomock.NewController(t)
    59  	cli = mocks.NewMockClient(mocker)
    60  	cli.EXPECT().
    61  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "", Name: "containerizedworkloads.core.oam.dev"}), gomock.Not(gomock.Nil()), gomock.Any()).
    62  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, wlDef *oamcore.WorkloadDefinition, opts ...client.GetOption) error {
    63  			wlDef.SetNamespace(key.Namespace)
    64  			wlDef.SetName(key.Name)
    65  			return nil
    66  		})
    67  	workload = unstructured.Unstructured{}
    68  	workload.SetGroupVersionKind(oamcore.ContainerizedWorkloadGroupVersionKind)
    69  	definition, err = FetchWorkloadDefinition(ctx, cli, vzlog.DefaultLogger(), &workload)
    70  	mocker.Finish()
    71  	assert.NoError(err)
    72  	assert.NotNil(definition)
    73  	assert.Equal("containerizedworkloads.core.oam.dev", definition.Name)
    74  
    75  	// GIVEN a valid workload reference
    76  	// WHEN an underlying error occurs with the k8s api
    77  	// THEN expect the error will be propagated
    78  	mocker = gomock.NewController(t)
    79  	cli = mocks.NewMockClient(mocker)
    80  	cli.EXPECT().
    81  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "", Name: "containerizedworkloads.core.oam.dev"}), gomock.Not(gomock.Nil()), gomock.Any()).
    82  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, wlDef *oamcore.WorkloadDefinition, opts ...client.GetOption) error {
    83  			return fmt.Errorf("test-error")
    84  		})
    85  	workload = unstructured.Unstructured{}
    86  	workload.SetGroupVersionKind(oamcore.ContainerizedWorkloadGroupVersionKind)
    87  	definition, err = FetchWorkloadDefinition(ctx, cli, vzlog.DefaultLogger(), &workload)
    88  	mocker.Finish()
    89  	assert.Error(err)
    90  	assert.Equal("test-error", err.Error())
    91  	assert.Nil(definition)
    92  }
    93  
    94  // TestFetchWorkloadChildren tests the FetchWorkloadChildren function.
    95  func TestFetchWorkloadChildren(t *testing.T) {
    96  	assert := asserts.New(t)
    97  
    98  	var mocker *gomock.Controller
    99  	var cli *mocks.MockClient
   100  	var ctx = context.TODO()
   101  	var err error
   102  	var workload unstructured.Unstructured
   103  	var children []*unstructured.Unstructured
   104  
   105  	// GIVEN a nil workload parameter
   106  	// WHEN the workload children are fetched
   107  	// THEN verify an error is returned
   108  	mocker = gomock.NewController(t)
   109  	cli = mocks.NewMockClient(mocker)
   110  	children, err = FetchWorkloadChildren(ctx, cli, vzlog.DefaultLogger(), nil)
   111  	mocker.Finish()
   112  	assert.Error(err)
   113  	assert.Len(children, 0)
   114  
   115  	// GIVEN a valid list of workload children
   116  	// WHEN the a workloads children are fetched
   117  	// THEN verify that the workload children are returned correctly.
   118  	mocker = gomock.NewController(t)
   119  	cli = mocks.NewMockClient(mocker)
   120  	// Expect a call to get the containerized workload definition and return one that populates the child resource kinds.
   121  	cli.EXPECT().
   122  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "", Name: "containerizedworkloads.core.oam.dev"}), gomock.Not(gomock.Nil()), gomock.Any()).
   123  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, wlDef *oamcore.WorkloadDefinition, opts ...client.GetOption) error {
   124  			wlDef.SetNamespace(key.Namespace)
   125  			wlDef.SetName(key.Name)
   126  			wlDef.Spec.ChildResourceKinds = []oamcore.ChildResourceKind{{APIVersion: "apps/v1", Kind: "Deployment"}}
   127  			return nil
   128  		})
   129  	// Expect a call to list the children resources and return a list.
   130  	options := []client.ListOption{client.InNamespace(namespace)}
   131  	cli.EXPECT().
   132  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), options).
   133  		DoAndReturn(func(ctx context.Context, resources *unstructured.UnstructuredList, opts ...client.ListOption) error {
   134  			assert.Equal("Deployment", resources.GetKind())
   135  			return AppendAsUnstructured(resources, k8sapps.Deployment{
   136  				TypeMeta: metav1.TypeMeta{
   137  					APIVersion: k8sapps.SchemeGroupVersion.String(),
   138  					Kind:       "test-invalid-kind"},
   139  				ObjectMeta: metav1.ObjectMeta{
   140  					Name: "test-deployment-name",
   141  					OwnerReferences: []metav1.OwnerReference{{
   142  						APIVersion: oamcore.ContainerizedWorkloadKindAPIVersion,
   143  						Kind:       oamcore.ContainerizedWorkloadKind,
   144  						Name:       "test-workload-name",
   145  						UID:        "test-workload-uid"}}}})
   146  		})
   147  	workload = unstructured.Unstructured{}
   148  	workload.SetGroupVersionKind(oamcore.ContainerizedWorkloadGroupVersionKind)
   149  	workload.SetNamespace(namespace)
   150  	workload.SetName("test-workload-name")
   151  	workload.SetUID("test-workload-uid")
   152  	children, err = FetchWorkloadChildren(ctx, cli, vzlog.DefaultLogger(), &workload)
   153  	mocker.Finish()
   154  	assert.NoError(err)
   155  	assert.Len(children, 1)
   156  	assert.Equal("test-deployment-name", children[0].GetName())
   157  
   158  	// GIVEN a request to fetch a workload's children
   159  	// WHEN an underlying kubernetes api error occurs
   160  	// THEN verify that the error is propagated to the caller.
   161  	mocker = gomock.NewController(t)
   162  	cli = mocks.NewMockClient(mocker)
   163  	cli.EXPECT().
   164  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "", Name: "containerizedworkloads.core.oam.dev"}), gomock.Not(gomock.Nil()), gomock.Any()).
   165  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, wlDef *oamcore.WorkloadDefinition, opts ...client.GetOption) error {
   166  			wlDef.SetNamespace(key.Namespace)
   167  			wlDef.SetName(key.Name)
   168  			wlDef.Spec.ChildResourceKinds = []oamcore.ChildResourceKind{{APIVersion: "apps/v1", Kind: "Deployment"}}
   169  			return nil
   170  		})
   171  	options = []client.ListOption{client.InNamespace(namespace)}
   172  	cli.EXPECT().
   173  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), options).
   174  		DoAndReturn(func(ctx context.Context, resources *unstructured.UnstructuredList, opts ...client.ListOption) error {
   175  			return fmt.Errorf("test-error")
   176  		})
   177  	workload = unstructured.Unstructured{}
   178  	workload.SetGroupVersionKind(oamcore.ContainerizedWorkloadGroupVersionKind)
   179  	workload.SetNamespace(namespace)
   180  	workload.SetName("test-workload-name")
   181  	workload.SetUID("test-workload-uid")
   182  	children, err = FetchWorkloadChildren(ctx, cli, vzlog.DefaultLogger(), &workload)
   183  	mocker.Finish()
   184  	assert.Error(err)
   185  	assert.Equal("test-error", err.Error())
   186  	assert.Len(children, 0)
   187  }
   188  
   189  // TestComponentFromWorkloadLabels tests the ComponentFromWorkloadLabels function.
   190  func TestComponentFromWorkloadLabels(t *testing.T) {
   191  	assert := asserts.New(t)
   192  
   193  	var mocker *gomock.Controller
   194  	var cli *mocks.MockClient
   195  	var ctx = context.TODO()
   196  
   197  	// GIVEN a nil workload labels
   198  	// WHEN an attempt is made to get the component
   199  	// THEN expect an error
   200  	mocker = gomock.NewController(t)
   201  	cli = mocks.NewMockClient(mocker)
   202  
   203  	component, err := ComponentFromWorkloadLabels(ctx, cli, "unit-test-namespace", nil)
   204  
   205  	mocker.Finish()
   206  	assert.EqualError(err, "OAM component label missing from metadata")
   207  	assert.Nil(component)
   208  
   209  	// GIVEN workload labels with just the component name
   210  	// WHEN an attempt is made to get the component
   211  	// THEN expect an error
   212  	mocker = gomock.NewController(t)
   213  	cli = mocks.NewMockClient(mocker)
   214  	labels := map[string]string{oam.LabelAppComponent: "unit-test-component"}
   215  
   216  	component, err = ComponentFromWorkloadLabels(ctx, cli, "unit-test-namespace", labels)
   217  
   218  	mocker.Finish()
   219  	assert.EqualError(err, "OAM app name label missing from metadata")
   220  	assert.Nil(component)
   221  
   222  	// GIVEN workload labels
   223  	// WHEN an attempt is made to get the component but there are no matching components in the returned app config
   224  	// THEN expect an error
   225  	mocker = gomock.NewController(t)
   226  	cli = mocks.NewMockClient(mocker)
   227  	labels = map[string]string{oam.LabelAppComponent: "unit-test-component", oam.LabelAppName: "unit-test-app-config"}
   228  
   229  	// expect a call to fetch the oam application configuration
   230  	cli.EXPECT().
   231  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "unit-test-namespace", Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   232  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   233  			component := oamcore.ApplicationConfigurationComponent{ComponentName: "does-not-match"}
   234  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   235  			return nil
   236  		})
   237  
   238  	component, err = ComponentFromWorkloadLabels(ctx, cli, "unit-test-namespace", labels)
   239  
   240  	mocker.Finish()
   241  	assert.EqualError(err, "unable to find application component for workload")
   242  	assert.Nil(component)
   243  
   244  	// GIVEN workload labels
   245  	// WHEN an attempt is made to get the component
   246  	// THEN validate that the expected component is returned
   247  	mocker = gomock.NewController(t)
   248  	cli = mocks.NewMockClient(mocker)
   249  	componentName := "unit-test-component"
   250  	labels = map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: "unit-test-app-config"}
   251  
   252  	// expect a call to fetch the oam application configuration
   253  	cli.EXPECT().
   254  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: "unit-test-namespace", Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   255  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   256  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName}
   257  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   258  			return nil
   259  		})
   260  
   261  	component, err = ComponentFromWorkloadLabels(ctx, cli, "unit-test-namespace", labels)
   262  
   263  	mocker.Finish()
   264  	assert.NoError(err)
   265  	assert.NotNil(component)
   266  	assert.Equal(componentName, component.ComponentName)
   267  }
   268  
   269  // TestIsVerrazzanoWorkloadKind tests the IsVerrazzanoWorkloadKind function.
   270  func TestIsVerrazzanoWorkloadKind(t *testing.T) {
   271  	assert := asserts.New(t)
   272  
   273  	// GIVEN a Verrazzano workload
   274  	// WHEN a call is made to check if the workload is a Verrazzano workload kind
   275  	// THEN expect the call to return true
   276  	workloadKind := "VerrazzanoCoherenceWorkload"
   277  
   278  	u := &unstructured.Unstructured{}
   279  	u.SetKind(workloadKind)
   280  
   281  	assert.True(IsVerrazzanoWorkloadKind(u))
   282  
   283  	// GIVEN a non-Verrazzano workload
   284  	// WHEN a call is made to check if the workload is a Verrazzano workload kind
   285  	// THEN expect the call to return false
   286  	workloadKind = "ContainerizedWorkload"
   287  
   288  	u = &unstructured.Unstructured{}
   289  	u.SetKind(workloadKind)
   290  
   291  	assert.False(IsVerrazzanoWorkloadKind(u))
   292  }
   293  
   294  // TestAPIVersionAndKindToContainedGVK tests the APIVersionAndKindToContainedGVK function.
   295  func TestAPIVersionAndKindToContainedGVK(t *testing.T) {
   296  	assert := asserts.New(t)
   297  
   298  	// GIVEN a known Verrazzano API version and workload kind
   299  	// WHEN a call is made to look up the contained GroupVersionKind
   300  	// THEN verify that the API version and kind are the expected values
   301  	gvk := APIVersionAndKindToContainedGVK(vzapi.SchemeGroupVersion.String(), "VerrazzanoCoherenceWorkload")
   302  
   303  	assert.NotNil(gvk)
   304  	apiVersion, kind := gvk.ToAPIVersionAndKind()
   305  	assert.Equal("coherence.oracle.com/v1", apiVersion)
   306  	assert.Equal("Coherence", kind)
   307  
   308  	// GIVEN an unknown Verrazzano API version and workload kind
   309  	// WHEN a call is made to look up the contained GroupVersionKind
   310  	// THEN verify that nil is returned
   311  	gvk = APIVersionAndKindToContainedGVK(vzapi.SchemeGroupVersion.String(), "BogusWorkload")
   312  
   313  	assert.Nil(gvk)
   314  }
   315  
   316  // TestWorkloadToContainedGVK tests the WorkloadToContainedGVK function.
   317  func TestWorkloadToContainedGVK(t *testing.T) {
   318  	assert := asserts.New(t)
   319  
   320  	// GIVEN an unstructured containing a known Verrazzano workload kind
   321  	// WHEN a call is made to look up the contained GroupVersionKind
   322  	// THEN verify that the API version and kind are the expected values
   323  	u := &unstructured.Unstructured{}
   324  	u.SetAPIVersion(vzapi.SchemeGroupVersion.String())
   325  	u.SetKind("VerrazzanoCoherenceWorkload")
   326  
   327  	gvk := WorkloadToContainedGVK(u)
   328  
   329  	assert.NotNil(gvk)
   330  	apiVersion, kind := gvk.ToAPIVersionAndKind()
   331  	assert.Equal("coherence.oracle.com/v1", apiVersion)
   332  	assert.Equal("Coherence", kind)
   333  
   334  	// GIVEN an unstructured containing an unknown Verrazzano workload kind
   335  	// WHEN a call is made to look up the contained GroupVersionKind
   336  	// THEN verify that nil is returned
   337  	u.SetKind("BogusWorkload")
   338  
   339  	gvk = WorkloadToContainedGVK(u)
   340  
   341  	assert.Nil(gvk)
   342  }
   343  
   344  // TestGetContainedWorkloadVersionKindName tests the GetContainedWorkloadVersionKindName function.
   345  func TestGetContainedWorkloadVersionKindName(t *testing.T) {
   346  	assert := asserts.New(t)
   347  
   348  	// GIVEN a Verrazzano workload containing another workload
   349  	// WHEN a call is made to get the api version, kind, and name of the contained workload
   350  	// THEN the api version, kind, and name are returned
   351  	workloadAPIVersion := "oam.verrazzano.io/v1alpha1"
   352  	workloadKind := "VerrazzanoCoherenceWorkload"
   353  
   354  	containedAPIVersion := "coherence.oracle.com/v1"
   355  	containedKind := "Coherence"
   356  	containedName := "unit-test-resource"
   357  
   358  	containedResource := map[string]interface{}{
   359  		"metadata": map[string]interface{}{
   360  			"name": containedName,
   361  		},
   362  	}
   363  
   364  	u := &unstructured.Unstructured{}
   365  	u.SetAPIVersion(workloadAPIVersion)
   366  	u.SetKind(workloadKind)
   367  	unstructured.SetNestedMap(u.Object, containedResource, "spec", "template")
   368  
   369  	apiVersion, kind, name, err := GetContainedWorkloadVersionKindName(u)
   370  
   371  	assert.Nil(err)
   372  	assert.Equal(containedAPIVersion, apiVersion)
   373  	assert.Equal(containedKind, kind)
   374  	assert.Equal(containedName, name)
   375  
   376  	// GIVEN a Verrazzano workload containing another workload where the Verrazzano workload is of an unknown kind
   377  	// WHEN a call is made to get the api version, kind, and name of the contained workload
   378  	// THEN an error is returned
   379  	workloadKind = "VerrazzanoBogusWorkload"
   380  
   381  	u = &unstructured.Unstructured{}
   382  	u.SetAPIVersion(workloadAPIVersion)
   383  	u.SetKind(workloadKind)
   384  
   385  	apiVersion, kind, name, err = GetContainedWorkloadVersionKindName(u)
   386  
   387  	assert.Error(err)
   388  	assert.True(strings.HasPrefix(err.Error(), "unable to find contained GroupVersionKind for workload"))
   389  	assert.Empty(apiVersion)
   390  	assert.Empty(kind)
   391  	assert.Empty(name)
   392  
   393  	// GIVEN a Verrazzano workload containing another workload missing the metadata name field
   394  	// WHEN a call is made to get the api version, kind, and name of the contained workload
   395  	// THEN an error is returned
   396  	workloadAPIVersion = "oam.verrazzano.io/v1alpha1"
   397  	workloadKind = "VerrazzanoCoherenceWorkload"
   398  
   399  	containedResource = map[string]interface{}{}
   400  
   401  	u = &unstructured.Unstructured{}
   402  	u.SetAPIVersion(workloadAPIVersion)
   403  	u.SetKind(workloadKind)
   404  	unstructured.SetNestedMap(u.Object, containedResource, "spec", "template")
   405  
   406  	apiVersion, kind, name, err = GetContainedWorkloadVersionKindName(u)
   407  
   408  	assert.Error(err)
   409  	assert.Equal("unable to find metadata name in contained workload", err.Error())
   410  	assert.Empty(apiVersion)
   411  	assert.Empty(kind)
   412  	assert.Empty(name)
   413  }
   414  
   415  // TestFetchContainedWorkload tests the FetchContainedWorkload function.
   416  func TestFetchContainedWorkload(t *testing.T) {
   417  	assert := asserts.New(t)
   418  
   419  	var mocker *gomock.Controller
   420  	var cli *mocks.MockClient
   421  	var ctx = context.TODO()
   422  
   423  	namespace := "unit-test-namespace"
   424  	workloadAPIVersion := "oam.verrazzano.io/v1alpha1"
   425  	workloadKind := "VerrazzanoCoherenceWorkload"
   426  
   427  	containedAPIVersion := "coherence.oracle.com/v1"
   428  	containedKind := "Coherence"
   429  	containedName := "unit-test-resource"
   430  
   431  	containedResource := map[string]interface{}{
   432  		"metadata": map[string]interface{}{
   433  			"name": containedName,
   434  		},
   435  	}
   436  
   437  	u := &unstructured.Unstructured{}
   438  	u.SetNamespace(namespace)
   439  	u.SetAPIVersion(workloadAPIVersion)
   440  	unstructured.SetNestedMap(u.Object, containedResource, "spec", "template")
   441  
   442  	// GIVEN a Verrazzano workload containing another workload
   443  	// WHEN a call is made to fetch the contained workload and the contained GroupVersionKind cannot be determined
   444  	// THEN validate that the call returns an error
   445  	mocker = gomock.NewController(t)
   446  	cli = mocks.NewMockClient(mocker)
   447  
   448  	u.SetKind("BogusWorkload")
   449  
   450  	contained, err := FetchContainedWorkload(ctx, cli, u)
   451  
   452  	assert.True(strings.HasPrefix(err.Error(), "unable to find contained GroupVersionKind for workload"))
   453  	assert.Nil(contained)
   454  
   455  	// GIVEN a Verrazzano workload containing another workload
   456  	// WHEN a call is made to fetch the contained workload and there is an error
   457  	// THEN validate that the call returns an error
   458  	mocker = gomock.NewController(t)
   459  	cli = mocks.NewMockClient(mocker)
   460  
   461  	u.SetKind(workloadKind)
   462  
   463  	// expect a call to get the contained resource, return an error
   464  	cli.EXPECT().
   465  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: namespace, Name: containedName}), gomock.Not(gomock.Nil()), gomock.Any()).
   466  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, contained *unstructured.Unstructured, opts ...client.GetOption) error {
   467  			return errors.NewNotFound(schema.GroupResource{}, "Unable to fetch resource")
   468  		})
   469  
   470  	contained, err = FetchContainedWorkload(ctx, cli, u)
   471  
   472  	assert.True(errors.IsNotFound(err))
   473  	assert.Nil(contained)
   474  
   475  	// GIVEN a Verrazzano workload containing another workload
   476  	// WHEN a call is made to fetch the contained workload
   477  	// THEN the call returns the contained workload
   478  	mocker = gomock.NewController(t)
   479  	cli = mocks.NewMockClient(mocker)
   480  
   481  	// expect a call to get the contained resource, return it as unstructured
   482  	cli.EXPECT().
   483  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: namespace, Name: containedName}), gomock.Not(gomock.Nil()), gomock.Any()).
   484  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, contained *unstructured.Unstructured, opts ...client.GetOption) error {
   485  			contained.SetUnstructuredContent(containedResource)
   486  			contained.SetAPIVersion(containedAPIVersion)
   487  			contained.SetKind(containedKind)
   488  			return nil
   489  		})
   490  
   491  	contained, err = FetchContainedWorkload(ctx, cli, u)
   492  
   493  	assert.Nil(err)
   494  	assert.Equal(containedAPIVersion, contained.GetAPIVersion())
   495  	assert.Equal(containedKind, contained.GetKind())
   496  	assert.Equal(containedName, contained.GetName())
   497  }
   498  
   499  // TestLoggingTraitFromWorkloadLabels tests the LoggingTraitFromWorkloadLabels function
   500  func TestLoggingTraitFromWorkloadLabels(t *testing.T) {
   501  	assert := asserts.New(t)
   502  
   503  	logger := vzlog.DefaultLogger()
   504  	ctx := context.TODO()
   505  
   506  	componentName := "unit-test-component"
   507  	componentNamespace := "unit-test-namespace"
   508  
   509  	ownerReferences := []metav1.OwnerReference{{
   510  		Name: "test-workload-name",
   511  		UID:  "test-workload-uid"}}
   512  
   513  	objectMeta := metav1.ObjectMeta{
   514  		Labels:          map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: "unit-test-app-config"},
   515  		OwnerReferences: ownerReferences,
   516  	}
   517  
   518  	// GIVEN a workload with no LoggingTrait
   519  	// WHEN a call to LoggingTraitFromWorkloadLabels is made
   520  	// THEN return nil
   521  	mocker := gomock.NewController(t)
   522  	cli := mocks.NewMockClient(mocker)
   523  
   524  	cli.EXPECT().
   525  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   526  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   527  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName}
   528  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   529  			return nil
   530  		})
   531  
   532  	result, err := LoggingTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   533  	assert.NoError(err)
   534  	assert.Nil(result)
   535  
   536  	item := vzapi.LoggingTrait{
   537  		TypeMeta: metav1.TypeMeta{
   538  			Kind: "LoggingTrait"},
   539  	}
   540  
   541  	// GIVEN a workload with associated LoggingTrait but no OwnerReferences
   542  	// WHEN a call to LoggingTraitFromWorkloadLabels is made
   543  	// THEN return an error
   544  	mocker = gomock.NewController(t)
   545  	cli = mocks.NewMockClient(mocker)
   546  
   547  	cli.EXPECT().
   548  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   549  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   550  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName,
   551  				Traits: []oamcore.ComponentTrait{{
   552  					Trait: runtime.RawExtension{Object: &item}},
   553  				}}
   554  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   555  			return nil
   556  		})
   557  
   558  	cli.EXPECT().
   559  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), client.InNamespace(componentNamespace)).
   560  		DoAndReturn(func(ctx context.Context, list *vzapi.LoggingTraitList, opts ...client.ListOption) error {
   561  			list.Items = []vzapi.LoggingTrait{item}
   562  			return nil
   563  		})
   564  
   565  	result, err = LoggingTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   566  	assert.Error(err)
   567  	assert.Nil(result)
   568  
   569  	item = vzapi.LoggingTrait{
   570  		TypeMeta: metav1.TypeMeta{
   571  			Kind: "LoggingTrait",
   572  		},
   573  		ObjectMeta: metav1.ObjectMeta{
   574  			Name:            "test-logging-trait",
   575  			OwnerReferences: ownerReferences,
   576  		},
   577  	}
   578  
   579  	// GIVEN a workload with associated LoggingTrait and OwnerReferences
   580  	// WHEN a call to LoggingTraitFromWorkloadLabels is made
   581  	// THEN return the associated LoggingTrait
   582  	mocker = gomock.NewController(t)
   583  	cli = mocks.NewMockClient(mocker)
   584  
   585  	cli.EXPECT().
   586  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   587  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   588  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName,
   589  				Traits: []oamcore.ComponentTrait{{
   590  					Trait: runtime.RawExtension{Object: &item}},
   591  				}}
   592  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   593  			return nil
   594  		})
   595  
   596  	cli.EXPECT().
   597  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), client.InNamespace(componentNamespace)).
   598  		DoAndReturn(func(ctx context.Context, list *vzapi.LoggingTraitList, opts ...client.ListOption) error {
   599  			list.Items = []vzapi.LoggingTrait{item}
   600  			return nil
   601  		})
   602  
   603  	result, err = LoggingTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   604  	assert.NoError(err)
   605  	assert.Equal(result.Name, "test-logging-trait")
   606  }
   607  
   608  // TestMetricsTraitFromWorkloadLabels tests the MetricsTraitFromWorkloadLabels function
   609  func TestMetricsTraitFromWorkloadLabels(t *testing.T) {
   610  	assert := asserts.New(t)
   611  
   612  	logger := zap.S().With("test")
   613  	ctx := context.TODO()
   614  
   615  	componentName := "unit-test-component"
   616  	componentNamespace := "unit-test-namespace"
   617  
   618  	ownerReferences := []metav1.OwnerReference{{
   619  		Name: "test-workload-name",
   620  		UID:  "test-workload-uid"}}
   621  
   622  	objectMeta := metav1.ObjectMeta{
   623  		Labels:          map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: "unit-test-app-config"},
   624  		OwnerReferences: ownerReferences,
   625  	}
   626  
   627  	// GIVEN a workload with no MetricsTrait
   628  	// WHEN a call to MetricsTraitFromWorkloadLabels is made
   629  	// THEN return nil
   630  	mocker := gomock.NewController(t)
   631  	cli := mocks.NewMockClient(mocker)
   632  
   633  	cli.EXPECT().
   634  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   635  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   636  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName}
   637  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   638  			return nil
   639  		})
   640  
   641  	result, err := MetricsTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   642  	assert.NoError(err)
   643  	assert.Nil(result)
   644  
   645  	item := vzapi.MetricsTrait{
   646  		TypeMeta: metav1.TypeMeta{
   647  			Kind: "MetricsTrait"},
   648  	}
   649  
   650  	// GIVEN a workload with associated MetricsTrait but no OwnerReferences
   651  	// WHEN a call to MetricsTraitFromWorkloadLabels is made
   652  	// THEN return an error
   653  	mocker = gomock.NewController(t)
   654  	cli = mocks.NewMockClient(mocker)
   655  
   656  	cli.EXPECT().
   657  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   658  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   659  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName,
   660  				Traits: []oamcore.ComponentTrait{{
   661  					Trait: runtime.RawExtension{Object: &item}},
   662  				}}
   663  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   664  			return nil
   665  		})
   666  
   667  	cli.EXPECT().
   668  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), client.InNamespace(componentNamespace)).
   669  		DoAndReturn(func(ctx context.Context, list *vzapi.MetricsTraitList, opts ...client.ListOption) error {
   670  			list.Items = []vzapi.MetricsTrait{item}
   671  			return nil
   672  		})
   673  
   674  	result, err = MetricsTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   675  	assert.Error(err)
   676  	assert.Nil(result)
   677  
   678  	item = vzapi.MetricsTrait{
   679  		TypeMeta: metav1.TypeMeta{
   680  			Kind: "MetricsTrait",
   681  		},
   682  		ObjectMeta: metav1.ObjectMeta{
   683  			Name:            "test-metrics-trait",
   684  			OwnerReferences: ownerReferences,
   685  		},
   686  	}
   687  
   688  	// GIVEN a workload with associated MetricsTrait and OwnerReferences
   689  	// WHEN a call to MetricsTraitFromWorkloadLabels is made
   690  	// THEN return the associated MetricsTrait
   691  	mocker = gomock.NewController(t)
   692  	cli = mocks.NewMockClient(mocker)
   693  
   694  	cli.EXPECT().
   695  		Get(gomock.Eq(ctx), gomock.Eq(client.ObjectKey{Namespace: componentNamespace, Name: "unit-test-app-config"}), gomock.Not(gomock.Nil()), gomock.Any()).
   696  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error {
   697  			component := oamcore.ApplicationConfigurationComponent{ComponentName: componentName,
   698  				Traits: []oamcore.ComponentTrait{{
   699  					Trait: runtime.RawExtension{Object: &item}},
   700  				}}
   701  			appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{component}
   702  			return nil
   703  		})
   704  
   705  	cli.EXPECT().
   706  		List(gomock.Eq(ctx), gomock.Not(gomock.Nil()), client.InNamespace(componentNamespace)).
   707  		DoAndReturn(func(ctx context.Context, list *vzapi.MetricsTraitList, opts ...client.ListOption) error {
   708  			list.Items = []vzapi.MetricsTrait{item}
   709  			return nil
   710  		})
   711  
   712  	result, err = MetricsTraitFromWorkloadLabels(ctx, cli, logger, componentNamespace, objectMeta)
   713  	assert.NoError(err)
   714  	assert.Equal(result.Name, "test-metrics-trait")
   715  }
   716  
   717  // TestIsOwnedByVerrazzanoWorkloadKind tests the IsOwnedByVerrazzanoWorkloadKind function
   718  // GIVEN a workload with OwnerReferences
   719  // WHEN a call to IsOwnedByVerrazzanoWorkloadKind is made
   720  // THEN return true is the workload is owned by VerrazzanoWorkloadKind, false otherwise
   721  func TestIsOwnedByVerrazzanoWorkloadKind(t *testing.T) {
   722  	assert := asserts.New(t)
   723  	workload := &unstructured.Unstructured{}
   724  
   725  	ownerReference := []metav1.OwnerReference{{
   726  		Name: "test-workload",
   727  		Kind: oamcore.ContainerizedWorkloadKind,
   728  	}}
   729  	verrazzanoOwnerReferences := []metav1.OwnerReference{{
   730  		Name: "test-verrazzano-workload",
   731  		Kind: "VerrazzanoCoherenceWorkload",
   732  	}}
   733  
   734  	workload.SetOwnerReferences(ownerReference)
   735  	assert.False(IsOwnedByVerrazzanoWorkloadKind(workload))
   736  
   737  	workload.SetOwnerReferences(verrazzanoOwnerReferences)
   738  	assert.True(IsOwnedByVerrazzanoWorkloadKind(workload))
   739  }