diff options
author | 2019-10-08 17:06:22 -0700 | |
---|---|---|
committer | 2019-10-08 17:26:38 -0700 | |
commit | d614d3d6cc1d40664215f79fc2c2f38af03a9996 (patch) | |
tree | 4432905d0db86ef353d46aeab89768454674c6f7 /vnfs/DAaaS/microservices/collectd-operator/pkg | |
parent | be2c15151b0258059d463d1c901c1a70f72d51f1 (diff) |
Collectd Operator Unit Tests
Added unit tests for Collectd operator.
Issue-ID: ONAPARC-461
Signed-off-by: Dileep Ranganathan <dileep.ranganathan@intel.com>
Change-Id: Ib50c16eaefc661e077d3477cbe8f2e4e62bbda80
Diffstat (limited to 'vnfs/DAaaS/microservices/collectd-operator/pkg')
9 files changed, 997 insertions, 14 deletions
diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdglobal_types.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdglobal_types.go index d5c69fbd..f14294e2 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdglobal_types.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdglobal_types.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package v1alpha1 import ( diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdplugin_types.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdplugin_types.go index eb338639..d814592b 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdplugin_types.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/apis/onap/v1alpha1/collectdplugin_types.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package v1alpha1 import ( diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller.go index 8c6023b8..d1bd5c6a 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package collectdglobal import ( diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller_test.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller_test.go new file mode 100644 index 00000000..2410fe6a --- /dev/null +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdglobal/collectdglobal_controller_test.go @@ -0,0 +1,536 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collectdglobal + +import ( + "context" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + onapv1alpha1 "collectd-operator/pkg/apis/onap/v1alpha1" + utils "collectd-operator/pkg/controller/utils" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" +) + +const ( + name = "collectd-operator" + namespace = "test1" + gOpts = "BaseDir \"/opt/collectd/var/lib/collectd\"\nPIDFile \"/opt/collectd/var/run/collectd.pid\"\nPluginDir" + + "\"/opt/collectd/lib/collectd\"\nTypesDB \"/opt/collectd/share/collectd/types.db\"\n" + + "#Hostname \"localhost\"\nInterval 1 \nWriteQueueLimitHigh" + + "10000000\nWriteQueueLimitLow 8000000\nTimeout \"10\"\nReadThreads \"50\"\nWriteThreads" + + "\"50\"\n\n#Enable plugins:\n\nLoadPlugin cpufreq\nLoadPlugin ipmi\nLoadPlugin" + + "turbostat\nLoadPlugin irq\nLoadPlugin memcached\nLoadPlugin memory\nLoadPlugin" + + "processes\nLoadPlugin load\n" + typesCmName = "types-configmap" + watchLabels = "app=collectd" +) + +var ( + one = intstr.FromInt(1) + ls, _ = labels.ConvertSelectorToLabelsMap(watchLabels) + cm = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cp-config-map", + Namespace: namespace, + Labels: ls, + }, + Data: map[string]string{ + "collectd.conf": "", + }, + } + typesCm = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: typesCmName, + Namespace: namespace, + Labels: ls, + }, + Data: map[string]string{ + "types.db": "types.db data", + }, + } + ds = &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cp-collectd", + Namespace: namespace, + Labels: ls, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: ls}, + UpdateStrategy: appsv1.DaemonSetUpdateStrategy{ + Type: appsv1.RollingUpdateDaemonSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateDaemonSet{ + MaxUnavailable: &one, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: ls, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{Name: "foo", Image: "bar"}}, + }, + }, + }, + } + + cp = &onapv1alpha1.CollectdPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cpu", + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdPluginSpec{ + PluginName: "cpu", + PluginConf: "Interval 10", + }, + } + + cpList = &onapv1alpha1.CollectdPluginList{ + Items: []onapv1alpha1.CollectdPlugin{}, + } +) + +// TestCollectdGlobalController runs ReconcileCollectdGlobal.Reconcile() against a +// fake client that tracks a CollectdGlobal object. + +// Reconcile No CR exist. +func TestCollectdGlobalNoCR(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + cg := &onapv1alpha1.CollectdGlobal{} + + cgList := &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{}, + } + + _ = cp + + // Objects to track in the fake client. + objs := []runtime.Object{ + cm, + ds, + cgList, + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cg, cgList, cpList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + res, err := rcg.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + // Check the result of reconciliation to make sure it has the desired state. + if res.Requeue { + t.Error("Unexpected Reconcile requeue request") + } +} + +// Test CollectdGlobalController - Add CR with non existent ConfigMap. +func TestCollectdGlobalNoCM(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + cg := &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + } + + cgList := &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{*cg}, + } + + _ = cp + + // Objects to track in the fake client. + objs := []runtime.Object{ + ds, + cgList, + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cg, cgList, cpList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } else { + t.Log("Successful Panic") + } + }() + res, err := rcg.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + // Check the result of reconciliation to make sure it has the desired state. + if !res.Requeue { + t.Error("Reconcile did not requeue request as expected") + } +} + +// Test CollectdGlobalController - HandleDelete +func TestCollectdGlobalHandleDelete(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + cg := &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + DeletionTimestamp: &metav1.Time{ + Time: time.Now(), + }, + Finalizers: []string{ + utils.CollectdFinalizer, + }, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + } + + cgList := &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{*cg}, + } + + _ = cp + + // Objects to track in the fake client. + objs := []runtime.Object{ + cm, + ds, + cgList, + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cg, cgList, cpList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + res, err := rcg.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + // Check the result of reconciliation to make sure it has the desired state. + if res.Requeue { + t.Error("Unexpected Reconcile requeue request") + } +} + +// Test CollectdGlobalController +func TestCollectdGlobalController(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + cg := &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + } + + cgList := &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{*cg}, + } + + _ = cp + + // Objects to track in the fake client. + objs := []runtime.Object{ + cm, + ds, + cgList, + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cg, cgList, cpList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + res, err := rcg.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + // Check the result of reconciliation to make sure it has the desired state. + if res.Requeue { + t.Error("Unexpected Reconcile requeue request") + } +} + +// Test HandleTypesDB +func TestHandleTypesDB(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + cg := &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + ConfigMap: typesCmName, + }, + } + + cgList := &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{*cg}, + } + + _ = cp + + testCases := []struct { + name string + createTypesCm bool + }{ + {name: "Handle TypesDB missing TypesDB ConfigMap", createTypesCm: false}, + {name: "Handle TypesDB", createTypesCm: true}, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + // Objects to track in the fake client. + objs := []runtime.Object{ + cm, + ds, + cgList, + } + if testCase.createTypesCm { + objs = append(objs, typesCm) + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cg, cgList, cpList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + res, err := rcg.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + // Check the result of reconciliation to make sure it has the desired state. + if res.Requeue { + t.Error("Unexpected Reconcile requeue request") + } + }) + } +} + +// Test UpdateStatus +func TestUpdateStatus(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + testCases := []struct { + name string + cg *onapv1alpha1.CollectdGlobal + createPods bool + expectedStatus string + expectedError error + }{ + { + name: "Update Status of New CR", + cg: &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + }, + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Initial state to Created", + cg: &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + Status: onapv1alpha1.CollectdGlobalStatus{ + Status: onapv1alpha1.Initial, + }, + }, + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Created state - No Pods", + cg: &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + Status: onapv1alpha1.CollectdGlobalStatus{ + Status: onapv1alpha1.Created, + }, + }, + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Created state to Enabled", + cg: &onapv1alpha1.CollectdGlobal{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdGlobalSpec{ + GlobalOptions: gOpts, + }, + Status: onapv1alpha1.CollectdGlobalStatus{ + Status: onapv1alpha1.Created, + }, + }, + createPods: true, + expectedStatus: onapv1alpha1.Enabled, + expectedError: nil, + }, + } + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + // Objects to track in the fake client. + objs := []runtime.Object{ + testCase.cg, + } + if testCase.createPods { + pods := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testCase.cg.Namespace, + Name: "cp-collectd-abcde", + Labels: ls, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + corev1.Container{ + Image: "collectd", + Name: "collectd", + }, + }, + }, + } + objs = append(objs, runtime.Object(pods)) + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, testCase.cg) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcg := &ReconcileCollectdGlobal{client: fc1, scheme: s} + + err := rcg.updateStatus(testCase.cg) + assert.Equal(t, testCase.expectedError, err) + // Fetch the CollectdGlobal instance + actual := &onapv1alpha1.CollectdGlobal{} + err = fc1.Get(context.TODO(), req.NamespacedName, actual) + assert.Equal(t, testCase.expectedStatus, actual.Status.Status) + if testCase.createPods { + assert.Equal(t, []string{"cp-collectd-abcde"}, actual.Status.CollectdAgents) + } + }) + } +} diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller.go index e0e62b87..6ad73782 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package collectdplugin import ( @@ -255,7 +268,7 @@ func (r *ReconcileCollectdPlugin) handleDelete(reqLogger logr.Logger, cr *onapv1 } func (r *ReconcileCollectdPlugin) updateStatus(cr *onapv1alpha1.CollectdPlugin) error { - // Fetch the CollectdGlobal instance + // Fetch the CollectdPlugin instance instance := &onapv1alpha1.CollectdPlugin{} key := types.NamespacedName{Namespace: cr.Namespace, Name: cr.Name} err := r.client.Get(context.TODO(), key, instance) diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller_test.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller_test.go new file mode 100644 index 00000000..f17aa6dc --- /dev/null +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/collectdplugin/collectdplugin_controller_test.go @@ -0,0 +1,370 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collectdplugin + +import ( + "context" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + onapv1alpha1 "collectd-operator/pkg/apis/onap/v1alpha1" + utils "collectd-operator/pkg/controller/utils" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" +) + +const ( + name = "cpu" + namespace = "test1" + gOpts = "BaseDir \"/opt/collectd/var/lib/collectd\"\nPIDFile \"/opt/collectd/var/run/collectd.pid\"\nPluginDir" + + "\"/opt/collectd/lib/collectd\"\nTypesDB \"/opt/collectd/share/collectd/types.db\"\n" + + "#Hostname \"localhost\"\nInterval 1 \nWriteQueueLimitHigh" + + "10000000\nWriteQueueLimitLow 8000000\nTimeout \"10\"\nReadThreads \"50\"\nWriteThreads" + + "\"50\"\n\n#Enable plugins:\n\nLoadPlugin cpufreq\nLoadPlugin ipmi\nLoadPlugin" + + "turbostat\nLoadPlugin irq\nLoadPlugin memcached\nLoadPlugin memory\nLoadPlugin" + + "processes\nLoadPlugin load\n" + typesCmName = "types-configmap" + watchLabels = "app=collectd" +) + +var ( + one = intstr.FromInt(1) + ls, _ = labels.ConvertSelectorToLabelsMap(watchLabels) + cgList = &onapv1alpha1.CollectdGlobalList{ + Items: []onapv1alpha1.CollectdGlobal{}, + } + cm = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cp-config-map", + Namespace: namespace, + Labels: ls, + }, + Data: map[string]string{ + "collectd.conf": "", + }, + } + readonlyCM = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cp-config-map-read-only", + Namespace: namespace, + Labels: ls, + }, + Data: map[string]string{ + "collectd.conf": "", + }, + } + typesCm = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: typesCmName, + Namespace: namespace, + Labels: ls, + }, + Data: map[string]string{ + "types.db": "types.db data", + }, + } + ds = &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cp-collectd", + Namespace: namespace, + Labels: ls, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: ls}, + UpdateStrategy: appsv1.DaemonSetUpdateStrategy{ + Type: appsv1.RollingUpdateDaemonSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateDaemonSet{ + MaxUnavailable: &one, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: ls, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{Name: "cp-collectd-1", Image: "collectd"}}, + }, + }, + }, + } + + cp1 = &onapv1alpha1.CollectdPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "CollectdPlugin", + APIVersion: "onap.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cpu", + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdPluginSpec{ + PluginName: "cpu", + PluginConf: "<Plugin cpu>\n" + + "ReportByCpu true\n" + + "ReportByState true\n" + + "ValuesPercentage true\n" + + "</Plugin>\n", + }, + } + + delCp1 = &onapv1alpha1.CollectdPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "CollectdPlugin", + APIVersion: "onap.org/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cpu", + Namespace: namespace, + DeletionTimestamp: &metav1.Time{ + Time: time.Now(), + }, + Finalizers: []string{ + utils.CollectdFinalizer, + }, + }, + Spec: onapv1alpha1.CollectdPluginSpec{ + PluginName: "cpu", + PluginConf: "<Plugin cpu>\n" + + "ReportByCpu true\n" + + "ReportByState true\n" + + "ValuesPercentage true\n" + + "</Plugin>\n", + }, + } + + cp2 = &onapv1alpha1.CollectdPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "write_prometheus", + Namespace: namespace, + }, + Spec: onapv1alpha1.CollectdPluginSpec{ + PluginName: "cpu", + PluginConf: "<Plugin write_prometheus>\n" + + "Port 9103\n" + + "</Plugin>\n", + }, + } + + cpList = &onapv1alpha1.CollectdPluginList{ + Items: []onapv1alpha1.CollectdPlugin{}, + } +) + +func TestReconcileCollectdPlugin_Reconcile(t *testing.T) { + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + tests := []struct { + name string + objs []runtime.Object + want reconcile.Result + wantErr bool + wantPanic bool + }{ + { + name: "CollectdPlugin Reconcile No CR", + objs: getObjs(nil, []runtime.Object{cm, ds}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + }, + { + name: "CollectdPlugin Add new CR cp1", + objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{cm, ds}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + }, + { + name: "CollectdPlugin Delete CR cp1", + objs: getObjs([]onapv1alpha1.CollectdPlugin{*delCp1}, []runtime.Object{cm, ds}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + }, + { + name: "CollectdPlugin Add new CR No configMap", + objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{ds}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + wantPanic: true, + }, + { + name: "CollectdPlugin Add new CR no DaemonSet", + objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{cm}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + wantPanic: true, + }, + { + name: "CollectdPlugin Add new CR cp2", + objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp2}, []runtime.Object{cm, ds}), + want: reconcile.Result{Requeue: false}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + if tt.wantPanic { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } else { + t.Log("Successful Panic") + } + }() + } + // Objects to track in the fake client. + objs := tt.objs + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cp1, cpList, cgList) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcp := &ReconcileCollectdPlugin{client: fc1, scheme: s} + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + got, err := rcp.Reconcile(req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + assert.Equal(t, tt.want, got) + }) + } +} + +// Test UpdateStatus +func TestUpdateStatus(t *testing.T) { + // Set the logger to development mode for verbose logs. + logf.SetLogger(logf.ZapLogger(true)) + + os.Setenv("WATCH_LABELS", watchLabels) + + testCases := []struct { + name string + cp *onapv1alpha1.CollectdPlugin + createPods bool + expectedStatus string + expectedError error + }{ + { + name: "Update Status of New CR", + cp: getNewCPWithStatus(cp1, onapv1alpha1.Initial), + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Initial state to Created", + cp: getNewCPWithStatus(cp1, onapv1alpha1.Created), + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Created state - No Pods", + cp: getNewCPWithStatus(cp1, onapv1alpha1.Created), + expectedStatus: onapv1alpha1.Created, + expectedError: nil, + }, + { + name: "Update Created state to Enabled", + cp: getNewCPWithStatus(cp1, onapv1alpha1.Created), + createPods: true, + expectedStatus: onapv1alpha1.Enabled, + expectedError: nil, + }, + } + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + // Objects to track in the fake client. + objs := []runtime.Object{ + testCase.cp, + } + if testCase.createPods { + pods := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testCase.cp.Namespace, + Name: "cp-collectd-abcde", + Labels: ls, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + corev1.Container{ + Image: "collectd", + Name: "collectd", + }, + }, + }, + } + objs = append(objs, runtime.Object(pods)) + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, testCase.cp) + + // Create a fake client to mock API calls + fc1 := fake.NewFakeClient(objs...) + rcp := &ReconcileCollectdPlugin{client: fc1, scheme: s} + + err := rcp.updateStatus(testCase.cp) + assert.Equal(t, testCase.expectedError, err) + // Fetch the CollectdGlobal instance + actual := &onapv1alpha1.CollectdPlugin{} + err = fc1.Get(context.TODO(), req.NamespacedName, actual) + assert.Equal(t, testCase.expectedStatus, actual.Status.Status) + if testCase.createPods { + assert.Equal(t, []string{"cp-collectd-abcde"}, actual.Status.CollectdAgents) + } + }) + } +} + +func getNewCPWithStatus(cp *onapv1alpha1.CollectdPlugin, status string) *onapv1alpha1.CollectdPlugin { + cpTemp := cp.DeepCopy() + cpTemp.Status.Status = status + return cpTemp +} + +func getObjs(cp []onapv1alpha1.CollectdPlugin, objs []runtime.Object) []runtime.Object { + cpL := cpList.DeepCopy() + cpL.Items = nil + items := append(cpL.Items, cp...) + cpL.Items = items + objs = append(objs, cpL) + return objs +} diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/collectdutils.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/collectdutils.go index b379d916..1e73f696 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/collectdutils.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/collectdutils.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package utils import ( diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/dsutils.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/dsutils.go index c5a44c44..1892b525 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/dsutils.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/dsutils.go @@ -1,3 +1,16 @@ +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package utils import ( diff --git a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/predicate.go b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/predicate.go index a9ec1dc4..a66e70ad 100644 --- a/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/predicate.go +++ b/vnfs/DAaaS/microservices/collectd-operator/pkg/controller/utils/predicate.go @@ -1,16 +1,15 @@ -// Copyright 2018 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* +Copyright 2019 Intel Corporation. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package utils |