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 }