github.com/verrazzano/verrazzano@v1.7.1/application-operator/controllers/wlsworkload/weblogicworkload_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 wlsworkload 5 6 import ( 7 "context" 8 "os" 9 "strings" 10 "testing" 11 12 "github.com/go-logr/logr" 13 14 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 15 16 oamrt "github.com/crossplane/crossplane-runtime/apis/common/v1" 17 "github.com/crossplane/oam-kubernetes-runtime/apis/core" 18 oamcore "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" 19 "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" 20 "github.com/golang/mock/gomock" 21 asserts "github.com/stretchr/testify/assert" 22 vzapi "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1" 23 "github.com/verrazzano/verrazzano/application-operator/constants" 24 "github.com/verrazzano/verrazzano/application-operator/controllers/logging" 25 "github.com/verrazzano/verrazzano/application-operator/controllers/metricstrait" 26 "github.com/verrazzano/verrazzano/application-operator/mocks" 27 vzconst "github.com/verrazzano/verrazzano/pkg/constants" 28 "go.uber.org/zap" 29 corev1 "k8s.io/api/core/v1" 30 k8serrors "k8s.io/apimachinery/pkg/api/errors" 31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 33 "k8s.io/apimachinery/pkg/runtime" 34 k8sschema "k8s.io/apimachinery/pkg/runtime/schema" 35 "k8s.io/apimachinery/pkg/types" 36 ctrl "sigs.k8s.io/controller-runtime" 37 "sigs.k8s.io/controller-runtime/pkg/client" 38 "sigs.k8s.io/yaml" 39 ) 40 41 const image = "unit-test-image:existing" 42 const clusterOne = "cluster-1" 43 const namespace = "unit-test-namespace" 44 const restartVersion = "new-restart" 45 const weblogicDomainName = "unit-test-domain" 46 const commonMetadata = `{"name":"unit-test-cluster"}` 47 const weblogicDomain = ` 48 { 49 "domainUID": "unit-test-domain" 50 } 51 ` 52 const weblogicDomainv9WithPV = ` 53 { 54 "clusters": [ 55 { 56 "name": "cluster-1" 57 } 58 ], 59 "configuration": { 60 "initializeDomainOnPV": { 61 "domain": { 62 "domainCreationImages": [ 63 { 64 "image": "phx.ocir.io/devweblogic/sankar-ai:aimiidemov1", 65 "sourceModelHome": "/u01/wdt/models", 66 "sourceWDTInstallHome": "/u01/wdt/weblogic-deploy" 67 } 68 ], 69 "domainType": "WLS" 70 }, 71 "persistentVolume": { 72 "metadata": { 73 "name": "unit-test-domain-pv" 74 }, 75 "spec": { 76 "capacity": { 77 "storage": "500Gi" 78 }, 79 "nfs": { 80 "path": "/shared", 81 "readOnly": false, 82 "server": "100.101.68.92" 83 }, 84 "storageClassName": "oci-fss" 85 } 86 }, 87 "persistentVolumeClaim": { 88 "metadata": { 89 "name": "unit-test-domain-pvc" 90 }, 91 "spec": { 92 "resources": { 93 "requests": { 94 "storage": "100Gi" 95 } 96 }, 97 "storageClassName": "oci-fss", 98 "volumeName": "unit-test-domain-pv" 99 } 100 } 101 }, 102 "introspectorJobActiveDeadlineSeconds": 900 103 }, 104 "domainHome": "/shared/domains/mymii-domain", 105 "domainHomeSourceType": "PersistentVolume", 106 "domainUID": "unit-test-domain", 107 "image": "phx.ocir.io/devweblogic/test-images/weblogic:14.1.1.0-11", 108 "imagePullPolicy": "IfNotPresent", 109 "serverPod": { 110 "env": [ 111 { 112 "name": "JAVA_OPTIONS", 113 "value": "-Dweblogic.StdoutDebugEnabled=false -Djava.security.egd=file:/dev/./urandom -Dweblogic.security.SSL.ignoreHostnameVerification=true" 114 }, 115 { 116 "name": "USER_MEM_ARGS", 117 "value": "-Xms64m -Xmx256m" 118 } 119 ], 120 "volumeMounts": [ 121 { 122 "mountPath": "/shared", 123 "name": "weblogic-domain-storage-volume" 124 }, 125 { 126 "mountPath": "/scratch", 127 "name": "weblogic-domain-scratch-volume" 128 } 129 ], 130 "volumes": [ 131 { 132 "name": "weblogic-domain-storage-volume", 133 "persistentVolumeClaim": { 134 "claimName": "mymii-domain-pvc" 135 } 136 }, 137 { 138 "name": "weblogic-domain-scratch-volume", 139 "persistentVolumeClaim": { 140 "claimName": "mymii-domain-pvc-scratch" 141 } 142 } 143 ] 144 } 145 } 146 ` 147 const weblogicDomainv9WithTwoClusters = ` 148 { 149 "domainUID": "unit-test-domain", 150 "clusters": [ 151 { 152 "clusterName": "cluster-1" 153 }, 154 { 155 "clusterName": "cluster-2" 156 } 157 ] 158 } 159 ` 160 const weblogicDomainWithMonitoringExporter = ` 161 { 162 "domainUID": "unit-test-domain", 163 "monitoringExporter": { 164 "image": "my-weblogic-monitoring-exporter:1.0.0", 165 "imagePullPolicy": "IfNotPresent", 166 "configuration": { 167 "metricsNameSnakeCase": true, 168 "domainQualifier": true, 169 "queries": [ 170 { 171 "JVMRuntime": { 172 "prefix": "wls_jvm_", 173 "key": "name" 174 } 175 } 176 ] 177 } 178 } 179 } 180 ` 181 const weblogicDomainWithWDTConfigMap = ` 182 { 183 "domainUID": "unit-test-domain", 184 "configuration": { 185 "model": { 186 "configMap": "wdt-config-map" 187 } 188 } 189 } 190 ` 191 const weblogicDomainWithLogHome = ` 192 { 193 "domainUID": "unit-test-domain", 194 "logHome": "/unit_test/log_home", 195 "serverPod": { 196 "volumes": [ 197 { 198 "name": "unit-test-logging-volume", 199 "persistentVolumeClaim": { 200 "claimName": "unit-test-pvc" 201 } 202 } 203 ], 204 "volumeMounts": [ 205 { 206 "name": "unit-test-logging-volume", 207 "mountPath": "/unit_test" 208 } 209 ] 210 } 211 } 212 ` 213 const loggingTrait = ` 214 { 215 "apiVersion": "oam.verrazzano.io/v1alpha1", 216 "kind": "LoggingTrait", 217 "name": "my-logging-trait" 218 } 219 ` 220 221 func buildTemplate(apiVersion string, metadata string, spec string) vzapi.VerrazzanoWebLogicWorkloadTemplate { 222 return vzapi.VerrazzanoWebLogicWorkloadTemplate{APIVersion: apiVersion, Metadata: runtime.RawExtension{Raw: []byte(metadata)}, Spec: runtime.RawExtension{Raw: []byte(strings.ReplaceAll(strings.ReplaceAll(spec, " ", ""), "\n", ""))}} 223 } 224 225 func buildDomainV8Template(spec string) vzapi.VerrazzanoWebLogicWorkloadTemplate { 226 return buildTemplate(APIVersionV8, commonMetadata, spec) 227 } 228 229 func buildDomainV9Template(spec string) vzapi.VerrazzanoWebLogicWorkloadTemplate { 230 return buildTemplate(APIVersionV9, commonMetadata, spec) 231 } 232 233 func buildClusterTemplate(name string) vzapi.VerrazzanoWebLogicWorkloadTemplate { 234 return buildTemplate(APIVersionV1, `{"name":"`+name+`"}`, `{"clusterName":"`+name+`"}`) 235 } 236 237 // TestReconcilerSetupWithManager test the creation of the VerrazzanoWebLogicWorkload reconciler. 238 // GIVEN a controller implementation 239 // WHEN the controller is created 240 // THEN verify no error is returned 241 func TestReconcilerSetupWithManager(t *testing.T) { 242 assert := asserts.New(t) 243 244 var mocker *gomock.Controller 245 var mgr *mocks.MockManager 246 var cli *mocks.MockClient 247 var scheme *runtime.Scheme 248 var reconciler Reconciler 249 var err error 250 251 mocker = gomock.NewController(t) 252 mgr = mocks.NewMockManager(mocker) 253 cli = mocks.NewMockClient(mocker) 254 scheme = runtime.NewScheme() 255 _ = vzapi.AddToScheme(scheme) 256 reconciler = Reconciler{Client: cli, Scheme: scheme} 257 mgr.EXPECT().GetControllerOptions().AnyTimes() 258 mgr.EXPECT().GetScheme().Return(scheme) 259 mgr.EXPECT().GetLogger().Return(logr.Discard()) 260 mgr.EXPECT().SetFields(gomock.Any()).Return(nil).AnyTimes() 261 mgr.EXPECT().Add(gomock.Any()).Return(nil).AnyTimes() 262 err = reconciler.SetupWithManager(mgr) 263 mocker.Finish() 264 assert.NoError(err) 265 } 266 267 // TestReconcileCreateWebLogicDomain tests the basic happy path of reconciling a VerrazzanoWebLogicWorkload. We 268 // expect to write out a WebLogic domain CR, but we aren't adding logging or any other scopes or traits. 269 // GIVEN a VerrazzanoWebLogicWorkload resource is created 270 // WHEN the controller Reconcile function is called 271 // THEN expect a WebLogic domain CR to be written 272 func TestReconcileCreateWebLogicDomain(t *testing.T) { 273 assert := asserts.New(t) 274 275 var mocker = gomock.NewController(t) 276 var cli = mocks.NewMockClient(mocker) 277 mockStatus := mocks.NewMockStatusWriter(mocker) 278 279 appConfigName := "unit-test-app-config" 280 componentName := "unit-test-component" 281 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 282 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 283 svcLabels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 284 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 285 286 // expect call to fetch existing WebLogic Domain 287 cli.EXPECT(). 288 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 289 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 290 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 291 }) 292 // expect a call to fetch the VerrazzanoWebLogicWorkload 293 cli.EXPECT(). 294 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 295 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 296 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 297 workload.ObjectMeta.Labels = labels 298 workload.APIVersion = vzapi.SchemeGroupVersion.String() 299 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 300 workload.Namespace = namespace 301 workload.ObjectMeta.Generation = 2 302 workload.Status.LastGeneration = "1" 303 return nil 304 }) 305 // expect a call to list the FLUENTD config maps 306 cli.EXPECT(). 307 List(gomock.Any(), gomock.Any(), gomock.Any()). 308 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 309 // return no resources 310 return nil 311 }) 312 // no config maps found, so expect a call to create a config map with our parsing rules 313 cli.EXPECT(). 314 Create(gomock.Any(), gomock.Any(), gomock.Any()). 315 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 316 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 317 return nil 318 }) 319 // expect call to fetch the WDT config Map 320 cli.EXPECT(). 321 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 322 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 323 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 324 }) 325 // no WDT config maps found, so expect a call to create a WDT config map 326 cli.EXPECT(). 327 Create(gomock.Any(), gomock.Any(), gomock.Any()). 328 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 329 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 330 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 331 assert.Equal(weblogicDomainName, configMap.ObjectMeta.Labels[webLogicDomainUIDLabel]) 332 return nil 333 }) 334 // expect a call to get the namespace for the domain 335 cli.EXPECT(). 336 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 337 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 338 return nil 339 }) 340 // expect a call to get the application configuration for the workload 341 cli.EXPECT(). 342 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 343 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 344 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 345 return nil 346 }).Times(2) 347 // expect a call to attempt to get the WebLogic CR - return not found 348 cli.EXPECT(). 349 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 350 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 351 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 352 }) 353 // expect a call to create the WebLogic domain CR 354 cli.EXPECT(). 355 Create(gomock.Any(), gomock.Any(), gomock.Any()). 356 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 357 assert.Equal(APIVersionV8, u.GetAPIVersion()) 358 assert.Equal(DomainKind, u.GetKind()) 359 360 // make sure the OAM component and app name labels were copied to the pod spec 361 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 362 assert.Equal(labels, specLabels) 363 364 // make sure the OAM component and app name labels were copied to the service spec 365 specServiceLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerServiceLabelsFields...) 366 assert.Equal(svcLabels, specServiceLabels) 367 368 // make sure configuration.istio.enabled is false 369 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 370 assert.Equal(specIstioEnabled, false) 371 372 // make sure the restartVersion is empty 373 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 374 assert.Equal("", domainRestartVersion) 375 376 // make sure monitoringExporter exists 377 validateDefaultMonitoringExporter(u, t) 378 379 // make sure default WDT configMap exists 380 validateDefaultWDTConfigMap(u, t) 381 382 return nil 383 }) 384 385 // expect a call to status update 386 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 387 388 // Expect a call to update the status of the Verrazzano resource to update components 389 mockStatus.EXPECT(). 390 Update(gomock.Any(), gomock.Any(), gomock.Any()). 391 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 392 return nil 393 }) 394 395 // create a request and reconcile it 396 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 397 reconciler := newReconciler(cli) 398 result, err := reconciler.Reconcile(context.TODO(), request) 399 400 mocker.Finish() 401 assert.NoError(err) 402 assert.Equal(false, result.Requeue) 403 } 404 405 // TestReconcileCreateWebLogicDomainV9WithPV tests the basic happy path of reconciling a VerrazzanoWebLogicWorkload. We 406 // expect to write out WebLogic Domain and Cluster CR's, but we aren't adding logging or any other scopes or traits. 407 // GIVEN a VerrazzanoWebLogicWorkload resource is created 408 // WHEN the controller Reconcile function is called 409 // THEN expect WebLogic Domain and Cluster CR's to be written 410 func TestReconcileCreateWebLogicDomainV9WithPV(t *testing.T) { 411 assert := asserts.New(t) 412 413 var mocker = gomock.NewController(t) 414 var cli = mocks.NewMockClient(mocker) 415 mockStatus := mocks.NewMockStatusWriter(mocker) 416 417 appConfigName := "unit-test-app-config" 418 componentName := "unit-test-component" 419 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 420 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 421 422 // expect call to fetch existing WebLogic Domain 423 cli.EXPECT(). 424 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 425 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 426 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 427 }) 428 // expect a call to fetch the VerrazzanoWebLogicWorkload 429 cli.EXPECT(). 430 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 431 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 432 workload.Spec.Template = buildDomainV9Template(weblogicDomainv9WithPV) 433 workload.Spec.Clusters = []vzapi.VerrazzanoWebLogicWorkloadTemplate{buildClusterTemplate(clusterOne)} 434 workload.ObjectMeta.Labels = labels 435 workload.APIVersion = vzapi.SchemeGroupVersion.String() 436 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 437 workload.Namespace = namespace 438 workload.ObjectMeta.Generation = 2 439 workload.Status.LastGeneration = "1" 440 return nil 441 }) 442 // expect a call to list the FLUENTD config maps 443 cli.EXPECT(). 444 List(gomock.Any(), gomock.Any(), gomock.Any()). 445 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 446 // return no resources 447 return nil 448 }) 449 // no config maps found, so expect a call to create a config map with our parsing rules 450 cli.EXPECT(). 451 Create(gomock.Any(), gomock.Any(), gomock.Any()). 452 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 453 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 454 return nil 455 }) 456 // expect call to fetch the WDT config Map 457 cli.EXPECT(). 458 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 459 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 460 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 461 }) 462 // no WDT config maps found, so expect a call to create a WDT config map 463 cli.EXPECT(). 464 Create(gomock.Any(), gomock.Any(), gomock.Any()). 465 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 466 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 467 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 468 assert.Equal(weblogicDomainName, configMap.ObjectMeta.Labels[webLogicDomainUIDLabel]) 469 return nil 470 }) 471 // expect a call to get the application configuration for the workload 472 cli.EXPECT(). 473 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 474 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 475 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 476 return nil 477 }).Times(2) 478 // expect call to fetch existing WebLogic Cluster cluster-1 479 cli.EXPECT(). 480 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: clusterOne}, gomock.Not(gomock.Nil()), gomock.Any()). 481 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 482 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 483 }) 484 // expect a call to attempt to get the WebLogic CR - return not found 485 cli.EXPECT(). 486 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 487 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 488 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 489 }) 490 // expect a call to create the WebLogic Cluster CR cluster-1 491 cli.EXPECT(). 492 Create(gomock.Any(), gomock.Any(), gomock.Any()). 493 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 494 assert.Equal(APIVersionV1, u.GetAPIVersion()) 495 assert.Equal(ClusterKind, u.GetKind()) 496 497 // make sure the OAM component and app name labels were copied 498 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 499 assert.Equal(labels, specLabels) 500 501 return nil 502 }) 503 // expect a call to create the WebLogic domain CR 504 cli.EXPECT(). 505 Create(gomock.Any(), gomock.Any(), gomock.Any()). 506 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 507 assert.Equal(APIVersionV9, u.GetAPIVersion()) 508 assert.Equal(DomainKind, u.GetKind()) 509 510 // make sure the OAM component and app name labels were copied 511 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 512 assert.Equal(labels, specLabels) 513 514 // make sure the restartVersion is empty 515 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 516 assert.Equal("", domainRestartVersion) 517 518 // make sure monitoringExporter exists 519 validateDefaultMonitoringExporter(u, t) 520 521 // make sure default WDT configMap exists 522 validatePVWDTConfigMap(u, t) 523 524 return nil 525 }) 526 527 // expect a call to status update 528 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 529 530 // Expect a call to update the status of the Verrazzano resource to update components 531 mockStatus.EXPECT(). 532 Update(gomock.Any(), gomock.Any(), gomock.Any()). 533 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 534 return nil 535 }) 536 537 // create a request and reconcile it 538 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 539 reconciler := newReconciler(cli) 540 result, err := reconciler.Reconcile(context.TODO(), request) 541 542 mocker.Finish() 543 assert.NoError(err) 544 assert.Equal(false, result.Requeue) 545 } 546 547 // TestReconcileCreateWebLogicDomainV9 tests the basic happy path of reconciling a VerrazzanoWebLogicWorkload. We 548 // expect to write out WebLogic Domain and Cluster CR's, but we aren't adding logging or any other scopes or traits. 549 // GIVEN a VerrazzanoWebLogicWorkload resource is created 550 // WHEN the controller Reconcile function is called 551 // THEN expect WebLogic Domain and Cluster CR's to be written 552 func TestReconcileCreateWebLogicDomainV9(t *testing.T) { 553 assert := asserts.New(t) 554 555 var mocker = gomock.NewController(t) 556 var cli = mocks.NewMockClient(mocker) 557 mockStatus := mocks.NewMockStatusWriter(mocker) 558 559 appConfigName := "unit-test-app-config" 560 componentName := "unit-test-component" 561 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 562 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 563 564 // expect call to fetch existing WebLogic Domain 565 cli.EXPECT(). 566 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 567 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 568 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 569 }) 570 // expect a call to fetch the VerrazzanoWebLogicWorkload 571 cli.EXPECT(). 572 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 573 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 574 workload.Spec.Template = buildDomainV9Template(weblogicDomainv9WithTwoClusters) 575 workload.Spec.Clusters = []vzapi.VerrazzanoWebLogicWorkloadTemplate{buildClusterTemplate(clusterOne), buildClusterTemplate("cluster-2")} 576 workload.ObjectMeta.Labels = labels 577 workload.APIVersion = vzapi.SchemeGroupVersion.String() 578 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 579 workload.Namespace = namespace 580 workload.ObjectMeta.Generation = 2 581 workload.Status.LastGeneration = "1" 582 return nil 583 }) 584 // expect a call to list the FLUENTD config maps 585 cli.EXPECT(). 586 List(gomock.Any(), gomock.Any(), gomock.Any()). 587 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 588 // return no resources 589 return nil 590 }) 591 // no config maps found, so expect a call to create a config map with our parsing rules 592 cli.EXPECT(). 593 Create(gomock.Any(), gomock.Any(), gomock.Any()). 594 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 595 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 596 return nil 597 }) 598 // expect call to fetch the WDT config Map 599 cli.EXPECT(). 600 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 601 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 602 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 603 }) 604 // no WDT config maps found, so expect a call to create a WDT config map 605 cli.EXPECT(). 606 Create(gomock.Any(), gomock.Any(), gomock.Any()). 607 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 608 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 609 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 610 assert.Equal(weblogicDomainName, configMap.ObjectMeta.Labels[webLogicDomainUIDLabel]) 611 return nil 612 }) 613 // expect a call to get the application configuration for the workload 614 cli.EXPECT(). 615 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 616 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 617 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 618 return nil 619 }).Times(2) 620 // expect call to fetch existing WebLogic Cluster cluster-1 621 cli.EXPECT(). 622 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: clusterOne}, gomock.Not(gomock.Nil()), gomock.Any()). 623 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 624 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 625 }) 626 // expect call to fetch existing WebLogic Cluster cluster-2 627 cli.EXPECT(). 628 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "cluster-2"}, gomock.Not(gomock.Nil()), gomock.Any()). 629 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 630 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 631 }) 632 // expect a call to attempt to get the WebLogic CR - return not found 633 cli.EXPECT(). 634 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 635 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 636 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 637 }) 638 // expect a call to create the WebLogic Cluster CR cluster-1 639 cli.EXPECT(). 640 Create(gomock.Any(), gomock.Any(), gomock.Any()). 641 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 642 assert.Equal(APIVersionV1, u.GetAPIVersion()) 643 assert.Equal(ClusterKind, u.GetKind()) 644 645 // make sure the OAM component and app name labels were copied 646 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 647 assert.Equal(labels, specLabels) 648 649 return nil 650 }) 651 // expect a call to create the WebLogic Cluster CR cluster-2 652 cli.EXPECT(). 653 Create(gomock.Any(), gomock.Any(), gomock.Any()). 654 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 655 assert.Equal(APIVersionV1, u.GetAPIVersion()) 656 assert.Equal(ClusterKind, u.GetKind()) 657 658 // make sure the OAM component and app name labels were copied 659 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 660 assert.Equal(labels, specLabels) 661 662 return nil 663 }) 664 // expect a call to create the WebLogic domain CR 665 cli.EXPECT(). 666 Create(gomock.Any(), gomock.Any(), gomock.Any()). 667 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 668 assert.Equal(APIVersionV9, u.GetAPIVersion()) 669 assert.Equal(DomainKind, u.GetKind()) 670 671 // make sure the OAM component and app name labels were copied 672 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 673 assert.Equal(labels, specLabels) 674 675 // make sure the restartVersion is empty 676 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 677 assert.Equal("", domainRestartVersion) 678 679 // make sure monitoringExporter exists 680 validateDefaultMonitoringExporter(u, t) 681 682 // make sure default WDT configMap exists 683 validateDefaultWDTConfigMap(u, t) 684 685 return nil 686 }) 687 688 // expect a call to status update 689 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 690 691 // Expect a call to update the status of the Verrazzano resource to update components 692 mockStatus.EXPECT(). 693 Update(gomock.Any(), gomock.Any(), gomock.Any()). 694 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 695 return nil 696 }) 697 698 // create a request and reconcile it 699 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 700 reconciler := newReconciler(cli) 701 result, err := reconciler.Reconcile(context.TODO(), request) 702 703 mocker.Finish() 704 assert.NoError(err) 705 assert.Equal(false, result.Requeue) 706 } 707 708 // TestReconcileCreateWebLogicDomainWithMonitoringExporter tests the basic happy path of reconciling a VerrazzanoWebLogicWorkload 709 // with monitoringExporter. We expect to write out a WebLogic domain CR with this monitoringExporter intact. 710 // GIVEN a VerrazzanoWebLogicWorkload resource is created 711 // WHEN the controller Reconcile function is called 712 // THEN expect a WebLogic domain CR to be written 713 func TestReconcileCreateWebLogicDomainWithMonitoringExporter(t *testing.T) { 714 assert := asserts.New(t) 715 716 var mocker = gomock.NewController(t) 717 var cli = mocks.NewMockClient(mocker) 718 mockStatus := mocks.NewMockStatusWriter(mocker) 719 720 appConfigName := "unit-test-app-config" 721 componentName := "unit-test-component" 722 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 723 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 724 725 // expect call to fetch existing WebLogic Domain 726 cli.EXPECT(). 727 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 728 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 729 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 730 }) 731 // expect a call to fetch the VerrazzanoWebLogicWorkload 732 cli.EXPECT(). 733 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 734 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 735 workload.Spec.Template = buildDomainV8Template(weblogicDomainWithMonitoringExporter) 736 workload.ObjectMeta.Labels = labels 737 workload.APIVersion = vzapi.SchemeGroupVersion.String() 738 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 739 workload.Namespace = namespace 740 workload.ObjectMeta.Generation = 2 741 workload.Status.LastGeneration = "1" 742 return nil 743 }) 744 // expect a call to list the FLUENTD config maps 745 cli.EXPECT(). 746 List(gomock.Any(), gomock.Any(), gomock.Any()). 747 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 748 // return no resources 749 return nil 750 }) 751 // no config maps found, so expect a call to create a config map with our parsing rules 752 cli.EXPECT(). 753 Create(gomock.Any(), gomock.Any(), gomock.Any()). 754 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 755 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 756 return nil 757 }) 758 // expect call to fetch the WDT config Map 759 cli.EXPECT(). 760 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 761 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 762 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 763 }) 764 // no WDT config maps found, so expect a call to create a WDT config map 765 cli.EXPECT(). 766 Create(gomock.Any(), gomock.Any(), gomock.Any()). 767 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 768 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 769 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 770 return nil 771 }) 772 // expect a call to get the namespace for the domain 773 cli.EXPECT(). 774 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 775 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 776 return nil 777 }) 778 // expect a call to get the application configuration for the workload 779 cli.EXPECT(). 780 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 781 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 782 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 783 return nil 784 }).Times(2) 785 // expect a call to attempt to get the WebLogic CR - return not found 786 cli.EXPECT(). 787 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 788 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 789 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 790 }) 791 // expect a call to create the WebLogic domain CR 792 cli.EXPECT(). 793 Create(gomock.Any(), gomock.Any(), gomock.Any()). 794 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 795 assert.Equal(APIVersionV8, u.GetAPIVersion()) 796 assert.Equal(DomainKind, u.GetKind()) 797 798 // make sure the OAM component and app name labels were copied 799 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 800 assert.Equal(labels, specLabels) 801 802 // make sure configuration.istio.enabled is false 803 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 804 assert.Equal(specIstioEnabled, false) 805 806 // make sure the restartVersion is empty 807 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 808 assert.Equal("", domainRestartVersion) 809 810 // make sure monitoringExporter exists 811 validateTestMonitoringExporter(u, t) 812 813 return nil 814 }) 815 816 // expect a call to status update 817 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 818 819 // Expect a call to update the status of the Verrazzano resource to update components 820 mockStatus.EXPECT(). 821 Update(gomock.Any(), gomock.Any(), gomock.Any()). 822 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 823 return nil 824 }) 825 826 // create a request and reconcile it 827 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 828 reconciler := newReconciler(cli) 829 result, err := reconciler.Reconcile(context.TODO(), request) 830 831 mocker.Finish() 832 assert.NoError(err) 833 assert.Equal(false, result.Requeue) 834 } 835 836 // TestReconcileCreateWebLogicDomainWithLogging tests the happy path of reconciling a VerrazzanoWebLogicWorkload 837 // with an attached logging scope. We expect to write out a WebLogic domain CR with the FLUENTD sidecar and 838 // associated volumes and mounts. 839 // GIVEN a VerrazzanoWebLogicWorkload resource is created with a logging scope 840 // WHEN the controller Reconcile function is called 841 // THEN expect a WebLogic domain CR to be written with logging extras. 842 func TestReconcileCreateWebLogicDomainWithLogging(t *testing.T) { 843 assert := asserts.New(t) 844 845 var mocker = gomock.NewController(t) 846 var cli = mocks.NewMockClient(mocker) 847 mockStatus := mocks.NewMockStatusWriter(mocker) 848 849 appConfigName := "unit-test-app-config" 850 componentName := "unit-test-component" 851 fluentdImage := "unit-test-image:latest" 852 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 853 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 854 855 _ = os.Setenv("WEBLOGIC_MONITORING_EXPORTER_IMAGE", "my-weblogic-monitoring-exporter:a") 856 defer func() { _ = os.Unsetenv("WEBLOGIC_MONITORING_EXPORTER_IMAGE") }() 857 858 // set the Fluentd image which is obtained via env then reset at end of test 859 initialDefaultFluentdImage := logging.DefaultFluentdImage 860 logging.DefaultFluentdImage = fluentdImage 861 defer func() { logging.DefaultFluentdImage = initialDefaultFluentdImage }() 862 863 // expect call to fetch existing WebLogic Domain 864 cli.EXPECT(). 865 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 866 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 867 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 868 }) 869 // expect a call to fetch the VerrazzanoWebLogicWorkload 870 cli.EXPECT(). 871 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 872 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 873 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 874 workload.ObjectMeta.Labels = labels 875 workload.APIVersion = vzapi.SchemeGroupVersion.String() 876 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 877 workload.Namespace = namespace 878 workload.ObjectMeta.Generation = 2 879 workload.Status.LastGeneration = "1" 880 return nil 881 }) 882 // expect a call to list the FLUENTD config maps 883 cli.EXPECT(). 884 List(gomock.Any(), gomock.Any(), gomock.Any()). 885 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 886 // return no resources 887 return nil 888 }) 889 // no config maps found, so expect a call to create a config map with our parsing rules 890 cli.EXPECT(). 891 Create(gomock.Any(), gomock.Any(), gomock.Any()). 892 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 893 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 894 return nil 895 }) 896 // expect call to fetch the WDT config Map 897 cli.EXPECT(). 898 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 899 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 900 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 901 }) 902 // no WDT config maps found, so expect a call to create a WDT config map 903 cli.EXPECT(). 904 Create(gomock.Any(), gomock.Any(), gomock.Any()). 905 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 906 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 907 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 908 return nil 909 }) 910 // expect a call to get the namespace for the domain 911 cli.EXPECT(). 912 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 913 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 914 return nil 915 }) 916 // expect a call to get the application configuration for the workload 917 cli.EXPECT(). 918 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 919 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 920 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 921 return nil 922 }).Times(2) 923 // expect a call to attempt to get the WebLogic CR - return not found 924 cli.EXPECT(). 925 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 926 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 927 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 928 }) 929 // expect a call to create the WebLogic domain CR 930 cli.EXPECT(). 931 Create(gomock.Any(), gomock.Any(), gomock.Any()). 932 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 933 assert.Equal(APIVersionV8, u.GetAPIVersion()) 934 assert.Equal(DomainKind, u.GetKind()) 935 936 // make sure the OAM component and app name labels were copied 937 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 938 assert.Equal(labels, specLabels) 939 940 // make sure configuration.istio.enabled is false 941 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 942 assert.Equal(specIstioEnabled, false) 943 944 // make sure the FLUENTD sidecar was added 945 containers, _, _ := unstructured.NestedSlice(u.Object, specServerPodContainersFields...) 946 assert.Equal(1, len(containers)) 947 assert.Equal(fluentdImage, containers[0].(map[string]interface{})["image"]) 948 949 // make sure the restartVersion is empty 950 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 951 assert.Equal("", domainRestartVersion) 952 953 // make sure monitoringExporter exists 954 validateDefaultMonitoringExporter(u, t) 955 956 return nil 957 }) 958 959 // expect a call to status update 960 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 961 962 // Expect a call to update the status of the Verrazzano resource to update components 963 mockStatus.EXPECT(). 964 Update(gomock.Any(), gomock.Any(), gomock.Any()). 965 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 966 // asserts.NotZero(len(verrazzano.Status.Components), "Status.Components len should not be zero") 967 return nil 968 }) 969 970 // create a request and reconcile it 971 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 972 reconciler := newReconciler(cli) 973 result, err := reconciler.Reconcile(context.TODO(), request) 974 975 mocker.Finish() 976 assert.NoError(err) 977 assert.Equal(false, result.Requeue) 978 } 979 980 // TestReconcileCreateWebLogicDomainWithCustomLogging tests the happy path of reconciling a VerrazzanoWebLogicWorkload 981 // with a custom logging trait. We expect to write out a WebLogic domain CR with an extra FLUENTD sidecar, 982 // ConfigMap, and associated volumes and mounts. 983 // GIVEN a VerrazzanoWebLogicWorkload resource is created with a custom logging trait 984 // WHEN the controller Reconcile function is called 985 // THEN expect a WebLogic domain CR to be written with custom logging extras. 986 func TestReconcileCreateWebLogicDomainWithCustomLogging(t *testing.T) { 987 assert := asserts.New(t) 988 989 var mocker = gomock.NewController(t) 990 var cli = mocks.NewMockClient(mocker) 991 mockStatus := mocks.NewMockStatusWriter(mocker) 992 993 appConfigName := "unit-test-app-config" 994 componentName := "unit-test-component" 995 workloadName := "unit-test-verrazzano-weblogic-workload" 996 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 997 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 998 999 // expect call to fetch existing WebLogic Domain 1000 cli.EXPECT(). 1001 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1002 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 1003 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 1004 }) 1005 // expect a call to fetch the VerrazzanoWebLogicWorkload 1006 cli.EXPECT(). 1007 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: workloadName}, gomock.Not(gomock.Nil()), gomock.Any()). 1008 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1009 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 1010 workload.ObjectMeta.Labels = labels 1011 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1012 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1013 workload.Namespace = namespace 1014 workload.Name = workloadName 1015 workload.ObjectMeta.Generation = 2 1016 workload.Status.LastGeneration = "1" 1017 workload.OwnerReferences = []metav1.OwnerReference{ 1018 { 1019 UID: namespace, 1020 }, 1021 } 1022 return nil 1023 }) 1024 // expect a call to list the logging traits 1025 cli.EXPECT(). 1026 List(gomock.Any(), &vzapi.LoggingTraitList{TypeMeta: metav1.TypeMeta{Kind: "LoggingTrait", APIVersion: "oam.verrazzano.io/v1alpha1"}}, gomock.Not(gomock.Nil())). 1027 DoAndReturn(func(ctx context.Context, loggingTraitList *vzapi.LoggingTraitList, inNamespace client.InNamespace) error { 1028 loggingTraitList.Items = []vzapi.LoggingTrait{ 1029 { 1030 ObjectMeta: metav1.ObjectMeta{ 1031 OwnerReferences: []metav1.OwnerReference{ 1032 { 1033 UID: namespace, 1034 }, 1035 }, 1036 }, 1037 Spec: vzapi.LoggingTraitSpec{ 1038 WorkloadReference: oamrt.TypedReference{ 1039 Name: workloadName, 1040 }, 1041 }, 1042 }, 1043 } 1044 return nil 1045 }) 1046 // expect a call to list the FLUENTD config maps 1047 cli.EXPECT(). 1048 List(gomock.Any(), gomock.Any(), gomock.Any()). 1049 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 1050 // return no resources 1051 return nil 1052 }) 1053 // Define expected ConfigMap 1054 data := make(map[string]string) 1055 data["custom.conf"] = "" 1056 customLoggingConfigMap := &corev1.ConfigMap{ 1057 TypeMeta: metav1.TypeMeta{ 1058 Kind: "", 1059 APIVersion: "", 1060 }, 1061 ObjectMeta: metav1.ObjectMeta{ 1062 Name: loggingNamePart + "-unit-test-cluster-domain", 1063 Namespace: namespace, 1064 CreationTimestamp: metav1.Time{}, 1065 OwnerReferences: []metav1.OwnerReference{ 1066 { 1067 APIVersion: "oam.verrazzano.io/v1alpha1", 1068 Kind: vzconst.VerrazzanoWebLogicWorkloadKind, 1069 Name: "unit-test-verrazzano-weblogic-workload", 1070 UID: "", 1071 Controller: newTrue(), 1072 BlockOwnerDeletion: newTrue(), 1073 }, 1074 }, 1075 }, 1076 Data: data, 1077 } 1078 // expect a call to create the custom logging config map 1079 cli.EXPECT(). 1080 Create(gomock.Any(), customLoggingConfigMap, gomock.Any()). 1081 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1082 return nil 1083 }) 1084 // no config maps found, so expect a call to create a config map with our parsing rules 1085 cli.EXPECT(). 1086 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1087 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1088 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 1089 return nil 1090 }) 1091 // expect call to fetch the WDT config Map 1092 cli.EXPECT(). 1093 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 1094 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1095 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 1096 }) 1097 // no WDT config maps found, so expect a call to create a WDT config map 1098 cli.EXPECT(). 1099 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1100 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1101 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 1102 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 1103 return nil 1104 }) 1105 // expect a call to get the namespace for the domain 1106 cli.EXPECT(). 1107 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 1108 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 1109 return nil 1110 }) 1111 // expect a call to get the application configuration for the workload 1112 cli.EXPECT(). 1113 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 1114 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1115 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{ 1116 { 1117 ComponentName: componentName, 1118 Traits: []oamcore.ComponentTrait{ 1119 { 1120 Trait: runtime.RawExtension{ 1121 Raw: []byte(strings.ReplaceAll(strings.ReplaceAll(loggingTrait, " ", ""), "\n", "")), 1122 }, 1123 }, 1124 }, 1125 }, 1126 } 1127 return nil 1128 }).Times(2) 1129 // expect a call to get the ConfigMap for logging - return not found 1130 cli.EXPECT(). 1131 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: "logging-stdout-unit-test-cluster-domain"}), gomock.Not(gomock.Nil()), gomock.Any()). 1132 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1133 return k8serrors.NewNotFound(k8sschema.GroupResource{ 1134 Group: "", 1135 Resource: "ConfigMap", 1136 }, 1137 "logging-stdout-unit-test-cluster-domain") 1138 }) 1139 // expect a call to attempt to get the WebLogic CR - return not found 1140 cli.EXPECT(). 1141 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 1142 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 1143 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 1144 }) 1145 // expect a call to create the WebLogic domain CR 1146 cli.EXPECT(). 1147 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1148 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 1149 assert.Equal(APIVersionV8, u.GetAPIVersion()) 1150 assert.Equal(DomainKind, u.GetKind()) 1151 1152 // make sure the OAM component and app name labels were copied 1153 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 1154 assert.Equal(labels, specLabels) 1155 1156 // make sure configuration.istio.enabled is false 1157 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 1158 assert.Equal(specIstioEnabled, false) 1159 1160 // make sure the restartVersion is empty 1161 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 1162 assert.Equal("", domainRestartVersion) 1163 1164 // make sure monitoringExporter exists 1165 validateDefaultMonitoringExporter(u, t) 1166 1167 // make sure default WDT configMap exists 1168 validateDefaultWDTConfigMap(u, t) 1169 1170 return nil 1171 }) 1172 1173 // expect a call to status update 1174 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1175 1176 // Expect a call to update the status of the Verrazzano resource to update components 1177 mockStatus.EXPECT(). 1178 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1179 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 1180 // asserts.NotZero(len(verrazzano.Status.Components), "Status.Components len should not be zero") 1181 return nil 1182 }) 1183 1184 // create a request and reconcile it 1185 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1186 reconciler := newReconciler(cli) 1187 result, err := reconciler.Reconcile(context.TODO(), request) 1188 1189 mocker.Finish() 1190 assert.NoError(err) 1191 assert.Equal(false, result.Requeue) 1192 } 1193 1194 // TestReconcileCreateWebLogicDomainWithCustomLogging tests the happy path of reconciling a VerrazzanoWebLogicWorkload 1195 // with a custom logging trait. We expect to write out a WebLogic domain CR with an extra FLUENTD sidecar 1196 // and associated volumes and mounts. This test, we are testing the case when the ConfigMap already exists 1197 // GIVEN a VerrazzanoWebLogicWorkload resource is created with a custom logging trait 1198 // WHEN the controller Reconcile function is called 1199 // THEN expect a WebLogic domain CR to be written with custom logging extras. 1200 func TestReconcileCreateWebLogicDomainWithCustomLoggingConfigMapExists(t *testing.T) { 1201 assert := asserts.New(t) 1202 1203 var mocker = gomock.NewController(t) 1204 var cli = mocks.NewMockClient(mocker) 1205 mockStatus := mocks.NewMockStatusWriter(mocker) 1206 1207 appConfigName := "unit-test-app-config" 1208 componentName := "unit-test-component" 1209 workloadName := "unit-test-verrazzano-weblogic-workload" 1210 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 1211 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 1212 1213 _ = os.Setenv("WEBLOGIC_MONITORING_EXPORTER_IMAGE", "") 1214 defer func() { _ = os.Unsetenv("WEBLOGIC_MONITORING_EXPORTER_IMAGE") }() 1215 1216 // expect call to fetch existing WebLogic Domain 1217 cli.EXPECT(). 1218 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1219 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 1220 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 1221 }) 1222 // expect a call to fetch the VerrazzanoWebLogicWorkload 1223 cli.EXPECT(). 1224 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: workloadName}, gomock.Not(gomock.Nil()), gomock.Any()). 1225 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1226 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 1227 workload.ObjectMeta.Labels = labels 1228 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1229 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1230 workload.Namespace = namespace 1231 workload.Name = workloadName 1232 workload.ObjectMeta.Generation = 2 1233 workload.Status.LastGeneration = "1" 1234 workload.OwnerReferences = []metav1.OwnerReference{ 1235 { 1236 UID: namespace, 1237 }, 1238 } 1239 return nil 1240 }) 1241 // expect a call to list the logging traits 1242 cli.EXPECT(). 1243 List(gomock.Any(), &vzapi.LoggingTraitList{TypeMeta: metav1.TypeMeta{Kind: "LoggingTrait", APIVersion: "oam.verrazzano.io/v1alpha1"}}, gomock.Not(gomock.Nil())). 1244 DoAndReturn(func(ctx context.Context, loggingTraitList *vzapi.LoggingTraitList, inNamespace client.InNamespace) error { 1245 loggingTraitList.Items = []vzapi.LoggingTrait{ 1246 { 1247 ObjectMeta: metav1.ObjectMeta{ 1248 OwnerReferences: []metav1.OwnerReference{ 1249 { 1250 UID: namespace, 1251 }, 1252 }, 1253 }, 1254 Spec: vzapi.LoggingTraitSpec{ 1255 WorkloadReference: oamrt.TypedReference{ 1256 Name: workloadName, 1257 }, 1258 }, 1259 }, 1260 } 1261 return nil 1262 }) 1263 // expect a call to list the FLUENTD config maps 1264 cli.EXPECT(). 1265 List(gomock.Any(), gomock.Any(), gomock.Any()). 1266 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 1267 // return no resources 1268 return nil 1269 }) 1270 // no config maps found, so expect a call to create a config map with our parsing rules 1271 cli.EXPECT(). 1272 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1273 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1274 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 1275 return nil 1276 }) 1277 // expect call to fetch the WDT config Map 1278 cli.EXPECT(). 1279 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 1280 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1281 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 1282 }) 1283 // no WDT config maps found, so expect a call to create a WDT config map 1284 cli.EXPECT(). 1285 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1286 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1287 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 1288 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 1289 return nil 1290 }) 1291 // expect a call to get the namespace for the domain 1292 cli.EXPECT(). 1293 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 1294 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 1295 return nil 1296 }) 1297 // expect a call to get the application configuration for the workload 1298 cli.EXPECT(). 1299 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 1300 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1301 1302 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{ 1303 { 1304 ComponentName: componentName, 1305 Traits: []oamcore.ComponentTrait{ 1306 { 1307 Trait: runtime.RawExtension{ 1308 Raw: []byte(strings.ReplaceAll(strings.ReplaceAll(loggingTrait, " ", ""), "\n", "")), 1309 }, 1310 }, 1311 }, 1312 }, 1313 } 1314 return nil 1315 }).Times(2) 1316 // expect a call to get the ConfigMap for logging 1317 cli.EXPECT(). 1318 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: "logging-stdout-unit-test-cluster-domain"}), gomock.Not(gomock.Nil()), gomock.Any()). 1319 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1320 return nil 1321 }) 1322 // expect a call to attempt to get the WebLogic CR - return not found 1323 cli.EXPECT(). 1324 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 1325 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 1326 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 1327 }) 1328 // expect a call to create the WebLogic domain CR 1329 cli.EXPECT(). 1330 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1331 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 1332 assert.Equal(APIVersionV8, u.GetAPIVersion()) 1333 assert.Equal(DomainKind, u.GetKind()) 1334 1335 // make sure the OAM component and app name labels were copied 1336 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 1337 assert.Equal(labels, specLabels) 1338 1339 // make sure configuration.istio.enabled is false 1340 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 1341 assert.Equal(specIstioEnabled, false) 1342 1343 // make sure the restartVersion is empty 1344 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 1345 assert.Equal("", domainRestartVersion) 1346 1347 // make sure monitoringExporter exists 1348 validateDefaultMonitoringExporter(u, t) 1349 1350 // make sure default WDT configMap exists 1351 validateDefaultWDTConfigMap(u, t) 1352 1353 return nil 1354 }) 1355 1356 // expect a call to status update 1357 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1358 1359 // Expect a call to update the status of the Verrazzano resource to update components 1360 mockStatus.EXPECT(). 1361 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1362 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 1363 // asserts.NotZero(len(verrazzano.Status.Components), "Status.Components len should not be zero") 1364 return nil 1365 }) 1366 1367 // create a request and reconcile it 1368 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1369 reconciler := newReconciler(cli) 1370 result, err := reconciler.Reconcile(context.TODO(), request) 1371 1372 mocker.Finish() 1373 assert.NoError(err) 1374 assert.Equal(false, result.Requeue) 1375 } 1376 1377 // TestReconcileCreateWebLogicDomainWithWDTConfigMap tests the basic happy path of reconciling a VerrazzanoWebLogicWorkload 1378 // with WDT configMap. We expect to update this configMap with default WebLogic plugin configuration details. 1379 // GIVEN a VerrazzanoWebLogicWorkload resource is created 1380 // WHEN the controller Reconcile function is called 1381 // THEN expect a WebLogic domain CR to be written with WDT configMap updated with WebLogic plugin configuration details. 1382 func TestReconcileCreateWebLogicDomainWithWDTConfigMap(t *testing.T) { 1383 assert := asserts.New(t) 1384 1385 var mocker = gomock.NewController(t) 1386 var cli = mocks.NewMockClient(mocker) 1387 mockStatus := mocks.NewMockStatusWriter(mocker) 1388 1389 appConfigName := "unit-test-app-config" 1390 componentName := "unit-test-component" 1391 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 1392 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 1393 1394 // expect call to fetch existing WebLogic Domain 1395 cli.EXPECT(). 1396 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1397 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 1398 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 1399 }) 1400 // expect a call to fetch the VerrazzanoWebLogicWorkload 1401 cli.EXPECT(). 1402 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1403 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1404 workload.Spec.Template = buildDomainV8Template(weblogicDomainWithWDTConfigMap) 1405 workload.ObjectMeta.Labels = labels 1406 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1407 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1408 workload.Namespace = namespace 1409 workload.ObjectMeta.Generation = 2 1410 workload.Status.LastGeneration = "1" 1411 return nil 1412 }) 1413 // expect a call to list the FLUENTD config maps 1414 cli.EXPECT(). 1415 List(gomock.Any(), gomock.Any(), gomock.Any()). 1416 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 1417 // return no resources 1418 return nil 1419 }) 1420 // no config maps found, so expect a call to create a config map with our parsing rules 1421 cli.EXPECT(). 1422 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1423 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1424 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 1425 return nil 1426 }) 1427 // expect a call to get the namespace for the domain 1428 cli.EXPECT(). 1429 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 1430 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 1431 return nil 1432 }) 1433 // expect a call to get the application configuration for the workload 1434 cli.EXPECT(). 1435 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 1436 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1437 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 1438 return nil 1439 }) 1440 1441 // expect call to fetch the WDT config map 1442 cli.EXPECT(). 1443 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "wdt-config-map"}, gomock.Any(), gomock.Any()). 1444 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1445 // set up a scaled down existing scrape config entry for cluster1 1446 configMap.Data = map[string]string{ 1447 "resources": "test", 1448 } 1449 return nil 1450 }) 1451 // WDT config map found, so expect a call to update a WDT config map 1452 cli.EXPECT(). 1453 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1454 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.UpdateOption) error { 1455 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 1456 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 1457 return nil 1458 }) 1459 1460 // expect a call to attempt to get the WebLogic CR - return not found 1461 cli.EXPECT(). 1462 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 1463 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 1464 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 1465 }) 1466 // expect a call to create the WebLogic domain CR 1467 cli.EXPECT(). 1468 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1469 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 1470 validateWDTConfigMap(u, t) 1471 return nil 1472 }) 1473 1474 // expect a call to status update 1475 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1476 1477 // Expect a call to update the status of the Verrazzano resource to update components 1478 mockStatus.EXPECT(). 1479 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1480 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 1481 return nil 1482 }) 1483 1484 // create a request and reconcile it 1485 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1486 reconciler := newReconciler(cli) 1487 result, err := reconciler.Reconcile(context.TODO(), request) 1488 1489 mocker.Finish() 1490 assert.NoError(err) 1491 assert.Equal(false, result.Requeue) 1492 } 1493 1494 // TestReconcileUpdateFluentdImage tests reconciling a VerrazzanoWebLogicWorkload when the Fluentd image 1495 // in the managed server pod sidecar is old and a new image is available. This should result in the latest Fluentd 1496 // image being pulled from the env and replaced in the sidecar 1497 // GIVEN a VerrazzanoWebLogicWorkload resource that is using an old Fluentd image 1498 // WHEN the controller Reconcile function is called 1499 // THEN the Fluentd image should be replaced in the Fluentd sidecar 1500 func TestReconcileUpdateFluentdImage(t *testing.T) { 1501 assert := asserts.New(t) 1502 1503 var mocker = gomock.NewController(t) 1504 var cli = mocks.NewMockClient(mocker) 1505 mockStatus := mocks.NewMockStatusWriter(mocker) 1506 1507 appConfigName := "unit-test-app-config" 1508 componentName := "unit-test-component" 1509 fluentdImage := "unit-test-image:latest" 1510 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 1511 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 1512 1513 // set the Fluentd image which is obtained via env then reset at end of test 1514 initialDefaultFluentdImage := logging.DefaultFluentdImage 1515 logging.DefaultFluentdImage = fluentdImage 1516 defer func() { logging.DefaultFluentdImage = initialDefaultFluentdImage }() 1517 1518 // expect call to fetch existing WebLogic Domain 1519 cli.EXPECT(). 1520 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1521 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 1522 // return nil error to simulate domain existing 1523 return nil 1524 }) 1525 // expect a call to fetch the VerrazzanoWebLogicWorkload 1526 cli.EXPECT(). 1527 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1528 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1529 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 1530 workload.ObjectMeta.Labels = labels 1531 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1532 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1533 workload.Namespace = namespace 1534 workload.ObjectMeta.Generation = 2 1535 workload.Status.LastGeneration = "1" 1536 return nil 1537 }) 1538 // expect a call to list the FLUENTD config maps 1539 cli.EXPECT(). 1540 List(gomock.Any(), gomock.Any(), gomock.Any()). 1541 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 1542 // return no resources 1543 return nil 1544 }) 1545 // no config maps found, so expect a call to create a config map with our parsing rules 1546 cli.EXPECT(). 1547 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1548 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1549 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 1550 return nil 1551 }) 1552 // expect call to fetch the WDT config Map 1553 cli.EXPECT(). 1554 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 1555 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1556 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 1557 }) 1558 // no WDT config maps found, so expect a call to create a WDT config map 1559 cli.EXPECT(). 1560 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1561 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1562 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 1563 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 1564 return nil 1565 }) 1566 // expect a call to get the namespace for the domain 1567 cli.EXPECT(). 1568 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 1569 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 1570 return nil 1571 }) 1572 // expect a call to attempt to get the VerrazzanoWebLogicWorkload CR 1573 cli.EXPECT(). 1574 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1575 DoAndReturn(func(ctx context.Context, name types.NamespacedName, u *unstructured.Unstructured, opts ...client.GetOption) error { 1576 // set the old Fluentd image on the returned obj 1577 containers, _, _ := unstructured.NestedSlice(u.Object, "spec", "serverPod", "containers") 1578 _ = unstructured.SetNestedField(containers[0].(map[string]interface{}), image, "image") 1579 _ = unstructured.SetNestedSlice(u.Object, containers, "spec", "serverPod", "containers") 1580 // return nil error because the VerrazzanoWebLogicWorkload CR exists 1581 return nil 1582 }) 1583 // expect a call to get the application configuration for the workload 1584 cli.EXPECT(). 1585 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 1586 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1587 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 1588 return nil 1589 }).Times(2) 1590 // expect a call to create the WebLogic domain CR 1591 cli.EXPECT(). 1592 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1593 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 1594 assert.Equal(APIVersionV8, u.GetAPIVersion()) 1595 assert.Equal(DomainKind, u.GetKind()) 1596 1597 // make sure the OAM component and app name labels were copied and the WebLogic type lobel applied 1598 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 1599 assert.Equal(3, len(specLabels)) 1600 assert.Equal("unit-test-component", specLabels["app.oam.dev/component"]) 1601 assert.Equal("unit-test-app-config", specLabels["app.oam.dev/name"]) 1602 assert.Equal(constants.WorkloadTypeWeblogic, specLabels[constants.LabelWorkloadType]) 1603 1604 // make sure the FLUENTD sidecar was added 1605 containers, _, _ := unstructured.NestedSlice(u.Object, specServerPodContainersFields...) 1606 assert.Equal(1, len(containers)) 1607 assert.Equal(fluentdImage, containers[0].(map[string]interface{})["image"]) 1608 1609 // make sure the restartVersion is empty 1610 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 1611 assert.Equal("", domainRestartVersion) 1612 1613 return nil 1614 }) 1615 1616 // expect a call to status update 1617 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1618 // expect a call to update the status upgrade version 1619 mockStatus.EXPECT(). 1620 Update(gomock.Any(), gomock.Any(), gomock.Any()). 1621 DoAndReturn(func(ctx context.Context, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 1622 return nil 1623 }) 1624 1625 // expect a call to status update 1626 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1627 1628 // create a request and reconcile it 1629 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1630 reconciler := newReconciler(cli) 1631 result, err := reconciler.Reconcile(context.TODO(), request) 1632 1633 mocker.Finish() 1634 assert.NoError(err) 1635 assert.Equal(false, result.Requeue) 1636 } 1637 1638 // TestReconcileErrorOnCreate tests reconciling a VerrazzanoWebLogicWorkload and an 1639 // error occurs attempting to create the WebLogic domain CR. 1640 // GIVEN a VerrazzanoWebLogicWorkload resource is created 1641 // WHEN the controller Reconcile function is called and there is an error creating the WebLogic domain CR 1642 // THEN expect an error to be returned 1643 func TestReconcileErrorOnCreate(t *testing.T) { 1644 assert := asserts.New(t) 1645 1646 var mocker = gomock.NewController(t) 1647 var cli = mocks.NewMockClient(mocker) 1648 mockStatus := mocks.NewMockStatusWriter(mocker) 1649 1650 appConfigName := "unit-test-app-config" 1651 componentName := "unit-test-component" 1652 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 1653 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 1654 1655 // expect call to fetch existing WebLogic Domain 1656 cli.EXPECT(). 1657 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 1658 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 1659 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 1660 }) 1661 // expect a call to fetch the VerrazzanoWebLogicWorkload 1662 cli.EXPECT(). 1663 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1664 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1665 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 1666 workload.ObjectMeta.Labels = labels 1667 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1668 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1669 workload.Namespace = namespace 1670 workload.ObjectMeta.Generation = 2 1671 workload.Status.LastGeneration = "1" 1672 return nil 1673 }) 1674 // expect a call to list the FLUENTD config maps 1675 cli.EXPECT(). 1676 List(gomock.Any(), gomock.Any(), gomock.Any()). 1677 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 1678 // return no resources 1679 return nil 1680 }) 1681 // no config maps found, so expect a call to create a config map with our parsing rules 1682 cli.EXPECT(). 1683 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1684 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1685 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 1686 return nil 1687 }) 1688 // expect call to fetch the WDT config Map 1689 cli.EXPECT(). 1690 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 1691 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 1692 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 1693 }) 1694 // no WDT config maps found, so expect a call to create a WDT config map 1695 cli.EXPECT(). 1696 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1697 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 1698 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 1699 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 1700 return nil 1701 }) 1702 // expect a call to get the namespace for the domain 1703 cli.EXPECT(). 1704 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 1705 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 1706 return nil 1707 }) 1708 // expect a call to get the application configuration for the workload 1709 cli.EXPECT(). 1710 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 1711 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1712 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 1713 return nil 1714 }).Times(2) 1715 // expect a call to attempt to get the WebLogic CR - return not found 1716 cli.EXPECT(). 1717 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 1718 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 1719 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 1720 }) 1721 // expect a call to create the WebLogic domain CR and return a BadRequest error 1722 cli.EXPECT(). 1723 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1724 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 1725 assert.Equal(APIVersionV8, u.GetAPIVersion()) 1726 assert.Equal(DomainKind, u.GetKind()) 1727 1728 // make sure the restartVersion is empty 1729 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 1730 assert.Equal("", domainRestartVersion) 1731 1732 return k8serrors.NewBadRequest("an error has occurred") 1733 }) 1734 1735 // expect a call to status update 1736 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 1737 1738 // create a request and reconcile it 1739 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1740 reconciler := newReconciler(cli) 1741 result, err := reconciler.Reconcile(context.TODO(), request) 1742 1743 mocker.Finish() 1744 assert.Nil(err) 1745 assert.True(result.Requeue) 1746 } 1747 1748 // TestReconcileWorkloadNotFound tests reconciling a VerrazzanoWebLogicWorkload when the workload 1749 // cannot be fetched. This happens when the workload has been deleted by the OAM runtime. 1750 // GIVEN a VerrazzanoWebLogicWorkload resource has been deleted 1751 // WHEN the controller Reconcile function is called and we attempt to fetch the workload 1752 // THEN return success from the controller as there is nothing more to do 1753 func TestReconcileWorkloadNotFound(t *testing.T) { 1754 assert := asserts.New(t) 1755 1756 var mocker = gomock.NewController(t) 1757 var cli = mocks.NewMockClient(mocker) 1758 1759 // expect a call to fetch the VerrazzanoWebLogicWorkload 1760 cli.EXPECT(). 1761 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1762 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1763 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 1764 }) 1765 1766 // create a request and reconcile it 1767 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1768 reconciler := newReconciler(cli) 1769 result, err := reconciler.Reconcile(context.TODO(), request) 1770 1771 mocker.Finish() 1772 assert.NoError(err) 1773 assert.Equal(false, result.Requeue) 1774 } 1775 1776 // TestReconcileFetchWorkloadError tests reconciling a VerrazzanoWebLogicWorkload when the workload 1777 // cannot be fetched due to an unexpected error. 1778 // GIVEN a VerrazzanoWebLogicWorkload resource has been created 1779 // WHEN the controller Reconcile function is called and we attempt to fetch the workload and get an error 1780 // THEN return the error 1781 func TestReconcileFetchWorkloadError(t *testing.T) { 1782 assert := asserts.New(t) 1783 1784 var mocker = gomock.NewController(t) 1785 var cli = mocks.NewMockClient(mocker) 1786 1787 // expect a call to fetch the VerrazzanoWebLogicWorkload 1788 cli.EXPECT(). 1789 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1790 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1791 return k8serrors.NewBadRequest("an error has occurred") 1792 }) 1793 1794 // create a request and reconcile it 1795 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1796 reconciler := newReconciler(cli) 1797 result, err := reconciler.Reconcile(context.TODO(), request) 1798 1799 mocker.Finish() 1800 assert.Nil(err) 1801 assert.Equal(true, result.Requeue) 1802 } 1803 1804 // TestCopyLabelsFailure tests reconciling a VerrazzanoWebLogicWorkload and we are 1805 // not able to copy labels to the WebLogic domain CR. 1806 // GIVEN a VerrazzanoWebLogicWorkload resource 1807 // WHEN the controller Reconcile function is called and the labels cannot be copied 1808 // THEN expect an error to be returned 1809 func TestCopyLabelsFailure(t *testing.T) { 1810 assert := asserts.New(t) 1811 1812 var mocker = gomock.NewController(t) 1813 var cli = mocks.NewMockClient(mocker) 1814 // mockStatus := mocks.NewMockStatusWriter(mocker) 1815 1816 // expect a call to fetch the VerrazzanoWebLogicWorkload - return a malformed WebLogic resource (spec should be an object 1817 // so when we attempt to set the labels field inside spec it will fail) - this is a contrived example, but it's the easiest 1818 // way to force error on copying labels 1819 cli.EXPECT(). 1820 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 1821 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 1822 json := `{27}` 1823 workload.Spec.Template = buildDomainV8Template(json) 1824 workload.APIVersion = vzapi.SchemeGroupVersion.String() 1825 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 1826 workload.ObjectMeta.Generation = 2 1827 workload.Status.LastGeneration = "1" 1828 return nil 1829 }) 1830 1831 // create a request and reconcile it 1832 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 1833 reconciler := newReconciler(cli) 1834 result, err := reconciler.Reconcile(context.TODO(), request) 1835 1836 mocker.Finish() 1837 assert.Nil(err) 1838 assert.Equal(true, result.Requeue) 1839 } 1840 1841 // TestCreateRuntimeEncryptionSecretCreate tests creation of a runtimeEncryptionSecret 1842 // GIVEN the runtime encryption secret does not exist 1843 // WHEN the controller CreateRuntimeEncryptionSecret function is called 1844 // THEN expect no error to be returned and runtime encryption secret is created 1845 func TestCreateRuntimeEncryptionSecretCreate(t *testing.T) { 1846 assert := asserts.New(t) 1847 1848 var mocker = gomock.NewController(t) 1849 var cli = mocks.NewMockClient(mocker) 1850 1851 // Expect a call to get a secret and return that it is not found. 1852 cli.EXPECT(). 1853 Get(gomock.Any(), types.NamespacedName{Namespace: "test-namespace", Name: "test-secret"}, gomock.Not(gomock.Nil()), gomock.Any()). 1854 Return(k8serrors.NewNotFound(k8sschema.GroupResource{Group: "test-space", Resource: "Secret"}, "test-space-secret")) 1855 1856 // Expect a call to get the appconfig resource to set the owner reference 1857 cli.EXPECT(). 1858 Get(gomock.Any(), types.NamespacedName{Namespace: "test-namespace", Name: "test-app"}, gomock.Not(gomock.Nil()), gomock.Any()). 1859 DoAndReturn(func(ctx context.Context, name types.NamespacedName, app *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 1860 app.TypeMeta = metav1.TypeMeta{ 1861 APIVersion: "core.oam.dev/v1alpha2", 1862 Kind: "ApplicationConfiguration", 1863 } 1864 return nil 1865 }) 1866 1867 // Expect a call to create the secret and return success 1868 cli.EXPECT(). 1869 Create(gomock.Any(), gomock.Any(), gomock.Any()). 1870 DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error { 1871 assert.Equal("Secret", secret.Kind) 1872 assert.Equal("v1", secret.APIVersion) 1873 assert.Len(secret.Data, 1) 1874 assert.Equal(1, len(secret.OwnerReferences)) 1875 assert.Equal("ApplicationConfiguration", secret.OwnerReferences[0].Kind) 1876 assert.Equal("core.oam.dev/v1alpha2", secret.OwnerReferences[0].APIVersion) 1877 return nil 1878 }) 1879 1880 scheme := runtime.NewScheme() 1881 _ = core.AddToScheme(scheme) 1882 _ = vzapi.AddToScheme(scheme) 1883 reconciler := Reconciler{Client: cli, Scheme: scheme} 1884 1885 workloadLabels := make(map[string]string) 1886 workloadLabels["app.oam.dev/name"] = "test-app" 1887 err := reconciler.createRuntimeEncryptionSecret(context.Background(), vzlog.DefaultLogger(), "test-namespace", "test-secret", workloadLabels) 1888 mocker.Finish() 1889 assert.NoError(err) 1890 } 1891 1892 // TestCreateRuntimeEncryptionSecretNoCreate tests that a runtimeEncryptionSecret already exist 1893 // GIVEN the runtime encryption secret exist 1894 // WHEN the controller createRuntimeEncryptionSecret function is called 1895 // THEN expect no error to be returned and runtime encryption secret is not created 1896 func TestCreateRuntimeEncryptionSecretNoCreate(t *testing.T) { 1897 assert := asserts.New(t) 1898 1899 var mocker = gomock.NewController(t) 1900 var cli = mocks.NewMockClient(mocker) 1901 1902 // Expect a call to get a secret and return that it was found. 1903 cli.EXPECT(). 1904 Get(gomock.Any(), types.NamespacedName{Namespace: "test-namespace", Name: "test-secret"}, gomock.Not(gomock.Nil()), gomock.Any()). 1905 DoAndReturn(func(ctx context.Context, name types.NamespacedName, dr *corev1.Secret, opts ...client.GetOption) error { 1906 dr.TypeMeta = metav1.TypeMeta{ 1907 APIVersion: "v1", 1908 Kind: "Secret"} 1909 return nil 1910 }) 1911 1912 scheme := runtime.NewScheme() 1913 _ = core.AddToScheme(scheme) 1914 _ = vzapi.AddToScheme(scheme) 1915 reconciler := Reconciler{Client: cli, Scheme: scheme} 1916 1917 workloadLabels := make(map[string]string) 1918 workloadLabels["app.oam.dev/name"] = "test-app" 1919 err := reconciler.createRuntimeEncryptionSecret(context.Background(), vzlog.DefaultLogger(), "test-namespace", "test-secret", workloadLabels) 1920 mocker.Finish() 1921 assert.NoError(err) 1922 } 1923 1924 // TestCreateRuntimeEncryptionSecretNoOamLabel tests creation of a runtime encryption secret with no oam label found 1925 // GIVEN no app.oam.dev/name label specified 1926 // WHEN the controller createRuntimeEncryptionSecret function is called 1927 // THEN expect an error to be returned 1928 func TestCreateRuntimeEncryptionSecretNoOamLabel(t *testing.T) { 1929 assert := asserts.New(t) 1930 1931 reconciler := Reconciler{} 1932 workloadLabels := make(map[string]string) 1933 err := reconciler.createRuntimeEncryptionSecret(context.Background(), vzlog.DefaultLogger(), "test-namespace", "test-secret", workloadLabels) 1934 assert.Equal("OAM app name label missing from metadata, unable to create owner reference to appconfig", err.Error()) 1935 } 1936 1937 // TestIstioEnabled tests that domain resource spec.configuration.istio.enabled is set correctly. 1938 // GIVEN istio-injection is enabled 1939 // THEN the domain resource to spec.configuration.istio.enabled is set to true 1940 func TestIstioEnabled(t *testing.T) { 1941 assert := asserts.New(t) 1942 1943 u := &unstructured.Unstructured{ 1944 Object: map[string]interface{}{ 1945 "kind": "Domain", 1946 }, 1947 } 1948 namespaceLabels := make(map[string]string) 1949 namespaceLabels["istio-injection"] = "enabled" 1950 err := updateIstioEnabled(namespaceLabels, u) 1951 assert.NoError(err, "Unexpected error setting istio enabled") 1952 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 1953 assert.Equal(specIstioEnabled, true) 1954 } 1955 1956 // TestIstioDisabled tests that domain resource spec.configuration.istio.enabled is set correctly. 1957 // GIVEN istio-injection is disabled 1958 // THEN the domain resource to spec.configuration.istio.enabled is set to false 1959 func TestIstioDisabled(t *testing.T) { 1960 assert := asserts.New(t) 1961 1962 u := &unstructured.Unstructured{ 1963 Object: map[string]interface{}{ 1964 "kind": "Domain", 1965 }, 1966 } 1967 namespaceLabels := make(map[string]string) 1968 namespaceLabels["istio-injection"] = "disabled" 1969 err := updateIstioEnabled(namespaceLabels, u) 1970 assert.NoError(err, "Unexpected error setting istio enabled") 1971 specIstioEnabled, _, _ := unstructured.NestedBool(u.Object, specConfigurationIstioEnabledFields...) 1972 assert.Equal(specIstioEnabled, false) 1973 } 1974 1975 // newScheme creates a new scheme that includes this package's object to use for testing 1976 func newScheme() *runtime.Scheme { 1977 scheme := runtime.NewScheme() 1978 _ = core.AddToScheme(scheme) 1979 _ = vzapi.AddToScheme(scheme) 1980 return scheme 1981 } 1982 1983 // newReconciler creates a new reconciler for testing 1984 // c - The K8s client to inject into the reconciler 1985 func newReconciler(c client.Client) Reconciler { 1986 scheme := newScheme() 1987 metricsReconciler := &metricstrait.Reconciler{Client: c, Scheme: scheme, Scraper: "verrazzano-system/vmi-system-prometheus-0"} 1988 return Reconciler{ 1989 Client: c, 1990 Log: zap.S().With("test"), 1991 Scheme: scheme, 1992 Metrics: metricsReconciler, 1993 } 1994 } 1995 1996 // newRequest creates a new reconciler request for testing 1997 // namespace - The namespace to use in the request 1998 // name - The name to use in the request 1999 func newRequest(namespace string, name string) ctrl.Request { 2000 return ctrl.Request{ 2001 NamespacedName: types.NamespacedName{ 2002 Namespace: namespace, 2003 Name: name, 2004 }, 2005 } 2006 } 2007 2008 // validateDefaultMonitoringExporter validates the default monitoringExporter in the WebLogic domain spec 2009 func validateDefaultMonitoringExporter(u *unstructured.Unstructured, t *testing.T) { 2010 _, found, err := unstructured.NestedFieldNoCopy(u.Object, specMonitoringExporterFields...) 2011 asserts.Nil(t, err, "Expect no error finding monitoringExporter in WebLogic domain CR") 2012 asserts.True(t, found, "Found monitoringExporter in WebLogic domain CR") 2013 imageName, _, _ := unstructured.NestedFieldNoCopy(u.Object, append(specMonitoringExporterFields, "image")...) 2014 if value := os.Getenv("WEBLOGIC_MONITORING_EXPORTER_IMAGE"); len(value) > 0 { 2015 asserts.Equal(t, value, imageName, "monitoringExporter.image should match in WebLogic domain CR") 2016 } else { 2017 asserts.Equal(t, nil, imageName, "monitoringExporter.image should match in WebLogic domain CR") 2018 } 2019 imagePullPolicy, _, _ := unstructured.NestedFieldNoCopy(u.Object, append(specMonitoringExporterFields, "imagePullPolicy")...) 2020 asserts.Equal(t, "IfNotPresent", imagePullPolicy, "monitoringExporter.imagePullPolicy should be IfNotPresent in WebLogic domain CR") 2021 domainQualifier, _, _ := unstructured.NestedBool(u.Object, append(specMonitoringExporterFields, "configuration", "domainQualifier")...) 2022 asserts.True(t, domainQualifier, "monitoringExporter.configuration.domainQualifier should be TRUE") 2023 metricsNameSnakeCase, _, _ := unstructured.NestedBool(u.Object, append(specMonitoringExporterFields, "configuration", "metricsNameSnakeCase")...) 2024 asserts.True(t, metricsNameSnakeCase, "monitoringExporter.configuration.metricsNameSnakeCase should be TRUE") 2025 queries, _, _ := unstructured.NestedSlice(u.Object, append(specMonitoringExporterFields, "configuration", "queries")...) 2026 asserts.Equal(t, 9, len(queries), "there should be 9 queries") 2027 query, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(&queries[0]) 2028 runtimeType, _, _ := unstructured.NestedString(query, "applicationRuntimes", "componentRuntimes", "type") 2029 asserts.Equal(t, "WebAppComponentRuntime", runtimeType, "query runtime type should be WebAppComponentRuntime") 2030 } 2031 2032 // validateTestMonitoringExporter validates the test monitoringExporter in the WebLogic domain spec 2033 func validateTestMonitoringExporter(u *unstructured.Unstructured, t *testing.T) { 2034 _, found, err := unstructured.NestedFieldNoCopy(u.Object, specMonitoringExporterFields...) 2035 asserts.Nil(t, err, "Expect no error finding monitoringExporter in WebLogic domain CR") 2036 asserts.True(t, found, "Found monitoringExporter in WebLogic domain CR") 2037 imageName, _, _ := unstructured.NestedFieldNoCopy(u.Object, append(specMonitoringExporterFields, "image")...) 2038 asserts.Equal(t, "my-weblogic-monitoring-exporter:1.0.0", imageName, "monitoringExporter.image should match in WebLogic domain CR") 2039 imagePullPolicy, _, _ := unstructured.NestedFieldNoCopy(u.Object, append(specMonitoringExporterFields, "imagePullPolicy")...) 2040 asserts.Equal(t, "IfNotPresent", imagePullPolicy, "monitoringExporter.imagePullPolicy should be IfNotPresent in WebLogic domain CR") 2041 domainQualifier, _, _ := unstructured.NestedBool(u.Object, append(specMonitoringExporterFields, "configuration", "domainQualifier")...) 2042 asserts.True(t, domainQualifier, "monitoringExporter.configuration.domainQualifier should be TRUE") 2043 metricsNameSnakeCase, _, _ := unstructured.NestedBool(u.Object, append(specMonitoringExporterFields, "configuration", "metricsNameSnakeCase")...) 2044 asserts.True(t, metricsNameSnakeCase, "monitoringExporter.configuration.metricsNameSnakeCase should be TRUE") 2045 queries, _, _ := unstructured.NestedSlice(u.Object, append(specMonitoringExporterFields, "configuration", "queries")...) 2046 asserts.Equal(t, 1, len(queries), "there should be 1 query") 2047 query, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(&queries[0]) 2048 jvmRuntimePrefix, _, _ := unstructured.NestedString(query, "JVMRuntime", "prefix") 2049 asserts.Equal(t, "wls_jvm_", jvmRuntimePrefix, "query JVMRuntime prefix should be wls_jvm_") 2050 } 2051 2052 // validateDefaultWDTConfigMap validates the default WDT config map in the WebLogic domain spec 2053 func validateDefaultWDTConfigMap(u *unstructured.Unstructured, t *testing.T) { 2054 mapName, found, err := unstructured.NestedString(u.Object, specConfigurationWDTConfigMap...) 2055 asserts.Nil(t, err, "Expect no error finding WDTConfigMap in WebLogic domain CR") 2056 asserts.True(t, found, "Found WDTConfigMap in WebLogic domain CR") 2057 asserts.Equal(t, mapName, getWDTConfigMapName(weblogicDomainName), "mapName should be ") 2058 } 2059 2060 // validatePVWDTConfigMap validates the default WDT config map in the WebLogic domain spec 2061 func validatePVWDTConfigMap(u *unstructured.Unstructured, t *testing.T) { 2062 mapName, found, err := unstructured.NestedString(u.Object, specConfigurationDomainOnPVConfigMap...) 2063 asserts.Nil(t, err, "Expect no error finding WDTConfigMap in WebLogic domain CR") 2064 asserts.True(t, found, "Found WDTConfigMap in WebLogic domain CR") 2065 asserts.Equal(t, mapName, getWDTConfigMapName(weblogicDomainName), "mapName should be ") 2066 } 2067 2068 // validateWDTConfigMap validates the WDT config name in the WebLogic domain spec 2069 func validateWDTConfigMap(u *unstructured.Unstructured, t *testing.T) { 2070 mapName, found, err := unstructured.NestedString(u.Object, specConfigurationWDTConfigMap...) 2071 asserts.Nil(t, err, "Expect no error finding WDTConfigMap in WebLogic domain CR") 2072 asserts.True(t, found, "Found WDTConfigMap in WebLogic domain CR") 2073 asserts.Equal(t, mapName, "wdt-config-map", "mapName should be ") 2074 } 2075 2076 // Used for bool in struct literal 2077 func newTrue() *bool { 2078 b := true 2079 return &b 2080 } 2081 2082 // TestGetWLSLogPath tests building the WebLogic log path 2083 func TestGetWLSLogPath(t *testing.T) { 2084 assert := asserts.New(t) 2085 2086 // GIVEN a call to getWLSLogPath 2087 // WHEN the logHome is not set 2088 // THEN the returned log path uses a generated base log path 2089 logPath := getWLSLogPath("", "test-domain") 2090 assert.Equal("/scratch/logs/test-domain/$(SERVER_NAME).log,/scratch/logs/test-domain/$(SERVER_NAME)_access.log,/scratch/logs/test-domain/$(SERVER_NAME)_nodemanager.log,/scratch/logs/test-domain/$(DOMAIN_UID).log", logPath) 2091 2092 // GIVEN a call to getWLSLogPath 2093 // WHEN the logHome is set 2094 // THEN the returned log path uses the provided logHome as the base path 2095 logPath = getWLSLogPath("/unit_test/log_home", "test-domain") 2096 assert.Equal("/unit_test/log_home/$(SERVER_NAME).log,/unit_test/log_home/$(SERVER_NAME)_access.log,/unit_test/log_home/$(SERVER_NAME)_nodemanager.log,/unit_test/log_home/$(DOMAIN_UID).log", logPath) 2097 } 2098 2099 // TestReconcileRestart tests reconciling a VerrazzanoWebLogicWorkload when the WebLogic 2100 // domain CR already exists and the restart-version specified in the annotations. 2101 // This should result in restartVersion written to the WLS domain . 2102 // GIVEN a VerrazzanoWebLogicWorkload resource 2103 // WHEN the controller Reconcile function is called and the WebLogic domain CR already exists and the restart-version is specified 2104 // THEN the WLS domain has restartVersion 2105 func TestReconcileRestart(t *testing.T) { 2106 assert := asserts.New(t) 2107 2108 var mocker = gomock.NewController(t) 2109 var cli = mocks.NewMockClient(mocker) 2110 2111 appConfigName := "unit-test-app-config" 2112 componentName := "unit-test-component" 2113 fluentdImage := "unit-test-image:latest" 2114 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 2115 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 2116 annotations := map[string]string{vzconst.RestartVersionAnnotation: restartVersion} 2117 mockStatus := mocks.NewMockStatusWriter(mocker) 2118 2119 // set the Fluentd image which is obtained via env then reset at end of test 2120 initialDefaultFluentdImage := logging.DefaultFluentdImage 2121 logging.DefaultFluentdImage = fluentdImage 2122 defer func() { logging.DefaultFluentdImage = initialDefaultFluentdImage }() 2123 2124 // expect call to fetch existing WebLogic Domain 2125 cli.EXPECT(). 2126 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2127 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 2128 // return nil error to simulate domain existing 2129 return nil 2130 }) 2131 // expect a call to fetch the VerrazzanoWebLogicWorkload 2132 cli.EXPECT(). 2133 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 2134 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 2135 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 2136 workload.ObjectMeta.Labels = labels 2137 workload.ObjectMeta.Annotations = annotations 2138 workload.APIVersion = vzapi.SchemeGroupVersion.String() 2139 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 2140 workload.Namespace = namespace 2141 workload.ObjectMeta.Generation = 2 2142 workload.Status.LastGeneration = "1" 2143 return nil 2144 }) 2145 // expect a call to list the FLUENTD config maps 2146 cli.EXPECT(). 2147 List(gomock.Any(), gomock.Any(), gomock.Any()). 2148 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 2149 // return no resources 2150 return nil 2151 }) 2152 // no config maps found, so expect a call to create a config map with our parsing rules 2153 cli.EXPECT(). 2154 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2155 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2156 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 2157 return nil 2158 }) 2159 // expect call to fetch the WDT config Map 2160 cli.EXPECT(). 2161 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 2162 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 2163 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 2164 }) 2165 // no WDT config maps found, so expect a call to create a WDT config map 2166 cli.EXPECT(). 2167 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2168 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2169 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 2170 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 2171 return nil 2172 }) 2173 // expect a call to get the namespace for the domain 2174 cli.EXPECT(). 2175 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 2176 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 2177 return nil 2178 }) 2179 // expect a call to attempt to get the domain CR 2180 cli.EXPECT(). 2181 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2182 DoAndReturn(func(ctx context.Context, name types.NamespacedName, u *unstructured.Unstructured, opts ...client.GetOption) error { 2183 // set the old Fluentd image on the returned obj 2184 containers, _, _ := unstructured.NestedSlice(u.Object, "spec", "serverPod", "containers") 2185 _ = unstructured.SetNestedField(containers[0].(map[string]interface{}), image, "image") 2186 _ = unstructured.SetNestedSlice(u.Object, containers, "spec", "serverPod", "containers") 2187 // return nil error because the VerrazzanoWebLogicWorkload CR StatefulSet exists 2188 return nil 2189 }) 2190 // expect a call to get the application configuration for the workload 2191 cli.EXPECT(). 2192 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 2193 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 2194 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 2195 return nil 2196 }).Times(2) 2197 // expect a call to create the WebLogic domain CR 2198 cli.EXPECT(). 2199 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2200 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.UpdateOption) error { 2201 assert.Equal(APIVersionV8, u.GetAPIVersion()) 2202 assert.Equal(DomainKind, u.GetKind()) 2203 2204 // make sure the OAM component and app name labels were copied and the WebLogic type lobel applied 2205 specLabels, _, _ := unstructured.NestedStringMap(u.Object, specServerPodLabelsFields...) 2206 assert.Equal(3, len(specLabels)) 2207 assert.Equal("unit-test-component", specLabels["app.oam.dev/component"]) 2208 assert.Equal("unit-test-app-config", specLabels["app.oam.dev/name"]) 2209 assert.Equal(constants.WorkloadTypeWeblogic, specLabels[constants.LabelWorkloadType]) 2210 2211 // make sure the FLUENTD sidecar was added 2212 containers, _, _ := unstructured.NestedSlice(u.Object, specServerPodContainersFields...) 2213 assert.Equal(1, len(containers)) 2214 assert.Equal(fluentdImage, containers[0].(map[string]interface{})["image"]) 2215 2216 // make sure the restartVersion was added to the domain 2217 domainRestartVersion, _, _ := unstructured.NestedString(u.Object, specRestartVersionFields...) 2218 assert.Equal(restartVersion, domainRestartVersion) 2219 2220 return nil 2221 }) 2222 2223 // expect a call to status update 2224 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 2225 2226 // Expect a call to update the status of the Verrazzano resource to update components 2227 mockStatus.EXPECT(). 2228 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2229 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 2230 // asserts.NotZero(len(verrazzano.Status.Components), "Status.Components len should not be zero") 2231 return nil 2232 }) 2233 2234 // create a request and reconcile it 2235 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 2236 reconciler := newReconciler(cli) 2237 result, err := reconciler.Reconcile(context.TODO(), request) 2238 2239 mocker.Finish() 2240 assert.NoError(err) 2241 assert.Equal(false, result.Requeue) 2242 } 2243 2244 // TestReconcileStopDomain tests reconciling a VerrazzanoWebLogicWorkload when the WebLogic 2245 // domain CR already exists and the lifecycle-action==stop is specified in the annotations. 2246 // GIVEN a VerrazzanoWebLogicWorkload resource 2247 // WHEN the controller Reconcile function is called and the WebLogic domain CR already exists and the restart-version is specified 2248 // THEN the WLS domain has restartVersion 2249 // 2250 // This should result in: 2251 // 1. NEVER written to the WLS domain serverStartPolicy 2252 // 2. The old serverStartPolicy saved in the domain annotation 2253 // 3. The WebLogic workload.Status.LastLifeCycleAction should have stop 2254 func TestReconcileStopDomain(t *testing.T) { 2255 assert := asserts.New(t) 2256 2257 var mocker = gomock.NewController(t) 2258 var cli = mocks.NewMockClient(mocker) 2259 2260 appConfigName := "unit-test-app-config" 2261 componentName := "unit-test-component" 2262 2263 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 2264 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 2265 annotations := map[string]string{vzconst.LifecycleActionAnnotation: vzconst.LifecycleActionStop} 2266 mockStatus := mocks.NewMockStatusWriter(mocker) 2267 2268 // expect call to fetch existing WebLogic Domain 2269 cli.EXPECT(). 2270 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2271 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 2272 // return nil error to simulate domain existing 2273 return nil 2274 }) 2275 // expect a call to fetch the VerrazzanoWebLogicWorkload 2276 cli.EXPECT(). 2277 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 2278 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 2279 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 2280 workload.ObjectMeta.Labels = labels 2281 workload.ObjectMeta.Annotations = annotations 2282 workload.APIVersion = vzapi.SchemeGroupVersion.String() 2283 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 2284 workload.Namespace = namespace 2285 workload.ObjectMeta.Generation = 2 2286 workload.Status.LastGeneration = "1" 2287 return nil 2288 }) 2289 // expect a call to list the FLUENTD config maps 2290 cli.EXPECT(). 2291 List(gomock.Any(), gomock.Any(), gomock.Any()). 2292 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 2293 // return no resources 2294 return nil 2295 }) 2296 // no config maps found, so expect a call to create a config map with our parsing rules 2297 cli.EXPECT(). 2298 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2299 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2300 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 2301 return nil 2302 }) 2303 // expect call to fetch the WDT config Map 2304 cli.EXPECT(). 2305 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 2306 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 2307 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 2308 }) 2309 // no WDT config maps found, so expect a call to create a WDT config map 2310 cli.EXPECT(). 2311 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2312 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2313 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 2314 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 2315 return nil 2316 }) 2317 // expect a call to get the namespace for the domain 2318 cli.EXPECT(). 2319 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 2320 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 2321 return nil 2322 }) 2323 // expect a call to attempt to get the WebLogic CR 2324 cli.EXPECT(). 2325 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2326 DoAndReturn(func(ctx context.Context, name types.NamespacedName, u *unstructured.Unstructured, opts ...client.GetOption) error { 2327 // set the old Fluentd image on the returned obj 2328 containers, _, _ := unstructured.NestedSlice(u.Object, "spec", "serverPod", "containers") 2329 _ = unstructured.SetNestedField(containers[0].(map[string]interface{}), image, "image") 2330 _ = unstructured.SetNestedSlice(u.Object, containers, "spec", "serverPod", "containers") 2331 // return nil error because the VerrazzanoWebLogicWorkload CR StatefulSet exists 2332 return nil 2333 }) 2334 // expect a call to get the application configuration for the workload 2335 cli.EXPECT(). 2336 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 2337 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 2338 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 2339 return nil 2340 }).Times(2) 2341 // expect a call to update the WebLogic domain CR 2342 cli.EXPECT(). 2343 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2344 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 2345 assert.Equal(APIVersionV8, u.GetAPIVersion()) 2346 assert.Equal(DomainKind, u.GetKind()) 2347 2348 // make sure the restartVersion was added to the domain 2349 policy, _, _ := unstructured.NestedString(u.Object, specServerStartPolicyFields...) 2350 assert.Equal(NeverV8, policy) 2351 2352 annos, _, _ := unstructured.NestedStringMap(u.Object, metaAnnotationFields...) 2353 assert.Equal(annos[lastServerStartPolicyAnnotation], IfNeededV8) 2354 return nil 2355 }) 2356 2357 // expect a call to status update 2358 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 2359 2360 // Expect a call to update the status of the Verrazzano resource to update components 2361 mockStatus.EXPECT(). 2362 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2363 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 2364 assert.Equal(vzconst.LifecycleActionStop, wl.Status.LastLifecycleAction) 2365 return nil 2366 }) 2367 2368 // create a request and reconcile it 2369 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 2370 reconciler := newReconciler(cli) 2371 result, err := reconciler.Reconcile(context.TODO(), request) 2372 2373 mocker.Finish() 2374 assert.NoError(err) 2375 assert.Equal(false, result.Requeue) 2376 } 2377 2378 // TestReconcileStartDomain tests reconciling a VerrazzanoWebLogicWorkload when the WebLogic 2379 // domain CR already exists and the lifecycle-action==start is specified in the annotations. 2380 // GIVEN a VerrazzanoWebLogicWorkload resource 2381 // WHEN the controller Reconcile function is called and the WebLogic domain CR already exists and the restart-version is specified 2382 // THEN the WLS domain has restartVersion 2383 // 2384 // This should result in: 2385 // 1. IF_NEEDED written to the WLS domain serverStartPolicy 2386 // 2. The WebLogic workload.Status.LastLifeCycleAction should have start 2387 func TestReconcileStartDomain(t *testing.T) { 2388 assert := asserts.New(t) 2389 2390 var mocker = gomock.NewController(t) 2391 var cli = mocks.NewMockClient(mocker) 2392 2393 appConfigName := "unit-test-app-config" 2394 componentName := "unit-test-component" 2395 2396 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 2397 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 2398 annotations := map[string]string{vzconst.LifecycleActionAnnotation: vzconst.LifecycleActionStart} 2399 mockStatus := mocks.NewMockStatusWriter(mocker) 2400 2401 // expect call to fetch existing WebLogic Domain 2402 cli.EXPECT(). 2403 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2404 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 2405 // return nil error to simulate domain existing 2406 return nil 2407 }) 2408 // expect a call to fetch the VerrazzanoWebLogicWorkload 2409 cli.EXPECT(). 2410 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 2411 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 2412 workload.Spec.Template = buildDomainV8Template(weblogicDomain) 2413 workload.ObjectMeta.Labels = labels 2414 workload.ObjectMeta.Annotations = annotations 2415 workload.APIVersion = vzapi.SchemeGroupVersion.String() 2416 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 2417 workload.Namespace = namespace 2418 workload.ObjectMeta.Generation = 2 2419 workload.Status.LastGeneration = "1" 2420 return nil 2421 }) 2422 // expect a call to list the FLUENTD config maps 2423 cli.EXPECT(). 2424 List(gomock.Any(), gomock.Any(), gomock.Any()). 2425 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 2426 // return no resources 2427 return nil 2428 }) 2429 // no config maps found, so expect a call to create a config map with our parsing rules 2430 cli.EXPECT(). 2431 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2432 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2433 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 2434 return nil 2435 }) 2436 // expect call to fetch the WDT config Map 2437 cli.EXPECT(). 2438 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 2439 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 2440 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 2441 }) 2442 // no WDT config maps found, so expect a call to create a WDT config map 2443 cli.EXPECT(). 2444 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2445 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2446 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 2447 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 2448 return nil 2449 }) 2450 // expect a call to get the namespace for the domain 2451 cli.EXPECT(). 2452 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 2453 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 2454 return nil 2455 }) 2456 // expect a call to attempt to get the WebLogic CR 2457 cli.EXPECT(). 2458 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2459 DoAndReturn(func(ctx context.Context, name types.NamespacedName, u *unstructured.Unstructured, opts ...client.GetOption) error { 2460 // set the old Fluentd image on the returned obj 2461 containers, _, _ := unstructured.NestedSlice(u.Object, "spec", "serverPod", "containers") 2462 _ = unstructured.SetNestedField(containers[0].(map[string]interface{}), image, "image") 2463 _ = unstructured.SetNestedSlice(u.Object, containers, "spec", "serverPod", "containers") 2464 // return nil error because the VerrazzanoWebLogicWorkload CR StatefulSet exists 2465 return nil 2466 }) 2467 // expect a call to get the application configuration for the workload 2468 cli.EXPECT(). 2469 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 2470 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 2471 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 2472 return nil 2473 }).Times(2) 2474 // expect a call to update the WebLogic domain CR 2475 cli.EXPECT(). 2476 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2477 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 2478 assert.Equal(APIVersionV8, u.GetAPIVersion()) 2479 assert.Equal(DomainKind, u.GetKind()) 2480 2481 // make sure the restartVersion was added to the domain 2482 policy, _, _ := unstructured.NestedString(u.Object, specServerStartPolicyFields...) 2483 assert.Equal(IfNeededV8, policy) 2484 2485 return nil 2486 }) 2487 2488 // expect a call to status update 2489 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 2490 2491 // Expect a call to update the status of the Verrazzano resource to update components 2492 mockStatus.EXPECT(). 2493 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2494 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 2495 assert.Equal(vzconst.LifecycleActionStart, wl.Status.LastLifecycleAction) 2496 return nil 2497 }) 2498 2499 // create a request and reconcile it 2500 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 2501 reconciler := newReconciler(cli) 2502 result, err := reconciler.Reconcile(context.TODO(), request) 2503 2504 mocker.Finish() 2505 assert.NoError(err) 2506 assert.Equal(false, result.Requeue) 2507 } 2508 2509 // TestReconcileKubeSystem tests to make sure we do not reconcile 2510 // Any resource that belong to the kube-system namespace 2511 func TestReconcileKubeSystem(t *testing.T) { 2512 assert := asserts.New(t) 2513 2514 var mocker = gomock.NewController(t) 2515 var cli = mocks.NewMockClient(mocker) 2516 2517 // create a request and reconcile it 2518 request := newRequest(vzconst.KubeSystem, "unit-test-verrazzano-helidon-workload") 2519 reconciler := newReconciler(cli) 2520 result, err := reconciler.Reconcile(context.TODO(), request) 2521 2522 // Validate the results 2523 mocker.Finish() 2524 assert.Nil(err) 2525 assert.True(result.IsZero()) 2526 } 2527 2528 // GIVEN a VerrazzanoWebLogicWorkload with a domain spec that has a logHome set 2529 // WHEN we reconcile the workload 2530 // THEN the Fluentd sidecar has the correct log paths, environment variable settings, volume, and volume mount 2531 // AND we do not overwrite the logHome setting 2532 func TestReconcileUserProvidedLogHome(t *testing.T) { 2533 assert := asserts.New(t) 2534 2535 var mocker = gomock.NewController(t) 2536 var cli = mocks.NewMockClient(mocker) 2537 mockStatus := mocks.NewMockStatusWriter(mocker) 2538 2539 appConfigName := "unit-test-app-config" 2540 componentName := "unit-test-component" 2541 labels := map[string]string{oam.LabelAppComponent: componentName, oam.LabelAppName: appConfigName, 2542 constants.LabelWorkloadType: constants.WorkloadTypeWeblogic} 2543 2544 // expect call to fetch existing WebLogic Domain 2545 cli.EXPECT(). 2546 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-cluster"}, gomock.Not(gomock.Nil()), gomock.Any()). 2547 DoAndReturn(func(ctx context.Context, name types.NamespacedName, domain *unstructured.Unstructured, opts ...client.GetOption) error { 2548 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "test") 2549 }) 2550 // expect a call to fetch the VerrazzanoWebLogicWorkload 2551 cli.EXPECT(). 2552 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: "unit-test-verrazzano-weblogic-workload"}, gomock.Not(gomock.Nil()), gomock.Any()). 2553 DoAndReturn(func(ctx context.Context, name types.NamespacedName, workload *vzapi.VerrazzanoWebLogicWorkload, opts ...client.GetOption) error { 2554 workload.Spec.Template = buildDomainV8Template(weblogicDomainWithLogHome) 2555 workload.ObjectMeta.Labels = labels 2556 workload.APIVersion = vzapi.SchemeGroupVersion.String() 2557 workload.Kind = vzconst.VerrazzanoWebLogicWorkloadKind 2558 workload.Namespace = namespace 2559 workload.ObjectMeta.Generation = 2 2560 workload.Status.LastGeneration = "1" 2561 return nil 2562 }) 2563 // expect a call to list the FLUENTD config maps 2564 cli.EXPECT(). 2565 List(gomock.Any(), gomock.Any(), gomock.Any()). 2566 DoAndReturn(func(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { 2567 // return no resources 2568 return nil 2569 }) 2570 // no config maps found, so expect a call to create a config map with our parsing rules 2571 cli.EXPECT(). 2572 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2573 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2574 assert.Equal(strings.Join(strings.Split(WlsFluentdParsingRules, "{{ .CAFile}}"), ""), configMap.Data["fluentd.conf"]) 2575 return nil 2576 }) 2577 // expect call to fetch the WDT config Map 2578 cli.EXPECT(). 2579 Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: getWDTConfigMapName(weblogicDomainName)}, gomock.Any(), gomock.Any()). 2580 DoAndReturn(func(ctx context.Context, name types.NamespacedName, configMap *corev1.ConfigMap, opts ...client.GetOption) error { 2581 return k8serrors.NewNotFound(k8sschema.GroupResource{}, getWDTConfigMapName(weblogicDomainName)) 2582 }) 2583 // no WDT config maps found, so expect a call to create a WDT config map 2584 cli.EXPECT(). 2585 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2586 DoAndReturn(func(ctx context.Context, configMap *corev1.ConfigMap, opts ...client.CreateOption) error { 2587 bytes, _ := yaml.JSONToYAML([]byte(defaultWDTConfigMapData)) 2588 assert.Equal(string(bytes), configMap.Data[webLogicPluginConfigYamlKey]) 2589 return nil 2590 }) 2591 // expect a call to get the namespace for the domain 2592 cli.EXPECT(). 2593 Get(gomock.Any(), gomock.Eq(client.ObjectKey{Namespace: "", Name: namespace}), gomock.Not(gomock.Nil()), gomock.Any()). 2594 DoAndReturn(func(ctx context.Context, key client.ObjectKey, namespace *corev1.Namespace, opts ...client.GetOption) error { 2595 return nil 2596 }) 2597 // expect a call to get the application configuration for the workload 2598 cli.EXPECT(). 2599 Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: namespace, Name: appConfigName}), gomock.Not(gomock.Nil()), gomock.Any()). 2600 DoAndReturn(func(ctx context.Context, name types.NamespacedName, appConfig *oamcore.ApplicationConfiguration, opts ...client.GetOption) error { 2601 appConfig.Spec.Components = []oamcore.ApplicationConfigurationComponent{{ComponentName: componentName}} 2602 return nil 2603 }).Times(2) 2604 // expect a call to attempt to get the WebLogic CR - return not found 2605 cli.EXPECT(). 2606 Get(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil()), gomock.Any()). 2607 DoAndReturn(func(ctx context.Context, key client.ObjectKey, u *unstructured.Unstructured, opts ...client.GetOption) error { 2608 return k8serrors.NewNotFound(k8sschema.GroupResource{}, "") 2609 }) 2610 // expect a call to create the WebLogic domain CR 2611 cli.EXPECT(). 2612 Create(gomock.Any(), gomock.Any(), gomock.Any()). 2613 DoAndReturn(func(ctx context.Context, u *unstructured.Unstructured, opts ...client.CreateOption) error { 2614 assert.Equal(APIVersionV8, u.GetAPIVersion()) 2615 assert.Equal(DomainKind, u.GetKind()) 2616 2617 const ( 2618 expectedLogHome = "/unit_test/log_home" 2619 expectedVolumeName = "unit-test-logging-volume" 2620 expectedVolumeMountPath = "/unit_test" 2621 ) 2622 2623 // make sure the user-specified logHome is set correctly 2624 logHome, _, _ := unstructured.NestedString(u.Object, specLogHomeFields...) 2625 assert.Equal(expectedLogHome, logHome) 2626 2627 // find the Fluentd container 2628 foundFluentdContainer := false 2629 containers, _, _ := unstructured.NestedSlice(u.Object, specServerPodContainersFields...) 2630 for _, container := range containers { 2631 c := container.(map[string]interface{}) 2632 if c["name"] == logging.FluentdStdoutSidecarName { 2633 foundFluentdContainer = true 2634 2635 // make sure the Fluentd container environment variables reference the correct logHome 2636 envs := c["env"].([]interface{}) 2637 assertEnvValueStartsWith(t, envs, "SERVER_LOG_PATH", expectedLogHome) 2638 assertEnvValueStartsWith(t, envs, "ACCESS_LOG_PATH", expectedLogHome) 2639 assertEnvValueStartsWith(t, envs, "NODEMANAGER_LOG_PATH", expectedLogHome) 2640 assertEnvValueStartsWith(t, envs, "DOMAIN_LOG_PATH", expectedLogHome) 2641 assertPathsStartWith(t, envs, "LOG_PATH", expectedLogHome) 2642 2643 // make sure the Fluentd container has the correct volume mount 2644 mounts := c["volumeMounts"].([]interface{}) 2645 assertVolumeMount(t, "Fluentd container", mounts, expectedVolumeName, expectedVolumeMountPath, expectedLogHome) 2646 } 2647 } 2648 assert.True(foundFluentdContainer, "Expected to find container with name %s", logging.FluentdStdoutSidecarName) 2649 2650 // make sure the serverPod volume mount is correct 2651 serverPod, _, _ := unstructured.NestedMap(u.Object, specServerPodFields...) 2652 assertVolumeMount(t, "serverPod", serverPod["volumeMounts"].([]interface{}), expectedVolumeName, expectedVolumeMountPath, expectedLogHome) 2653 2654 // make sure the serverPod volume has not been overwritten 2655 assertVolume(t, serverPod["volumes"].([]interface{}), expectedVolumeName, "unit-test-pvc") 2656 2657 return nil 2658 }) 2659 2660 // expect a call to status update 2661 cli.EXPECT().Status().Return(mockStatus).AnyTimes() 2662 2663 // expect a call to update the status of the Verrazzano resource to update components 2664 mockStatus.EXPECT(). 2665 Update(gomock.Any(), gomock.Any(), gomock.Any()). 2666 DoAndReturn(func(ctx context.Context, wl *vzapi.VerrazzanoWebLogicWorkload, opts ...client.UpdateOption) error { 2667 return nil 2668 }) 2669 2670 // create a request and reconcile it 2671 request := newRequest(namespace, "unit-test-verrazzano-weblogic-workload") 2672 reconciler := newReconciler(cli) 2673 result, err := reconciler.Reconcile(context.TODO(), request) 2674 2675 mocker.Finish() 2676 assert.NoError(err) 2677 assert.Equal(false, result.Requeue) 2678 } 2679 2680 // assertEnvValueStartsWith asserts that the named environment variable value starts with the specified string 2681 func assertEnvValueStartsWith(t *testing.T, envs []interface{}, name string, startsWith string) { 2682 assert := asserts.New(t) 2683 2684 for _, env := range envs { 2685 e := env.(map[string]interface{}) 2686 if e["name"] == name { 2687 v := e["value"].(string) 2688 assert.True(strings.HasPrefix(v, startsWith), "Expected %s value %s to start with %s", name, v, startsWith) 2689 return 2690 } 2691 } 2692 assert.Fail("Failed", "Unable to find env var named %s", name) 2693 } 2694 2695 // assertPathsStartWith asserts that each path in the comma-delimited string value (identified by the env var name) starts 2696 // with the specified string 2697 func assertPathsStartWith(t *testing.T, envs []interface{}, name string, startsWith string) { 2698 assert := asserts.New(t) 2699 2700 for _, env := range envs { 2701 e := env.(map[string]interface{}) 2702 if e["name"] == name { 2703 for _, path := range strings.Split(e["value"].(string), ",") { 2704 assert.True(strings.HasPrefix(path, startsWith), "Expected %s path %s to start with %s", name, path, startsWith) 2705 return 2706 } 2707 } 2708 } 2709 assert.Fail("Failed", "Unable to find env var named %s", name) 2710 } 2711 2712 // assertVolumeMount asserts that the volume mount's mount path is correct and is a prefix of the log path 2713 func assertVolumeMount(t *testing.T, context string, mounts []interface{}, volumeName string, mountPath string, logPath string) { 2714 assert := asserts.New(t) 2715 2716 for _, mount := range mounts { 2717 m := mount.(map[string]interface{}) 2718 if m["name"] == volumeName { 2719 mp := m["mountPath"].(string) 2720 assert.Equal(mountPath, mp) 2721 assert.True(strings.HasPrefix(logPath, mp), "Expected %s volume mount %s mount path %s to be a prefix of %s", context, volumeName, mp, logPath) 2722 return 2723 } 2724 } 2725 assert.Fail("Failed", "Unable to find volume mount named %s in %s", volumeName, context) 2726 } 2727 2728 // assertVolume asserts that the specified volume has the specified persistent volume claim name 2729 func assertVolume(t *testing.T, volumes []interface{}, volumeName string, claimName string) { 2730 assert := asserts.New(t) 2731 2732 for _, volume := range volumes { 2733 v := volume.(map[string]interface{}) 2734 if v["name"] == volumeName { 2735 if pvc, ok := v["persistentVolumeClaim"]; ok { 2736 pvcName := pvc.(map[string]interface{})["claimName"] 2737 assert.Equal(claimName, pvcName) 2738 return 2739 } 2740 assert.Fail("Failed", "Unable to find persistentVolumeClaim in volume named %s", volumeName) 2741 return 2742 } 2743 } 2744 assert.Fail("Failed", "Unable to find volume named %s", volumeName) 2745 }