2 Copyright 2019 Intel Corporation.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
14 package collectdplugin
22 "github.com/stretchr/testify/assert"
24 onapv1alpha1 "collectd-operator/pkg/apis/onap/v1alpha1"
25 utils "collectd-operator/pkg/controller/utils"
27 appsv1 "k8s.io/api/apps/v1"
28 corev1 "k8s.io/api/core/v1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/labels"
31 "k8s.io/apimachinery/pkg/runtime"
32 "k8s.io/apimachinery/pkg/types"
33 "k8s.io/apimachinery/pkg/util/intstr"
34 "k8s.io/client-go/kubernetes/scheme"
35 "sigs.k8s.io/controller-runtime/pkg/client/fake"
36 "sigs.k8s.io/controller-runtime/pkg/reconcile"
37 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
43 gOpts = "BaseDir \"/opt/collectd/var/lib/collectd\"\nPIDFile \"/opt/collectd/var/run/collectd.pid\"\nPluginDir" +
44 "\"/opt/collectd/lib/collectd\"\nTypesDB \"/opt/collectd/share/collectd/types.db\"\n" +
45 "#Hostname \"localhost\"\nInterval 1 \nWriteQueueLimitHigh" +
46 "10000000\nWriteQueueLimitLow 8000000\nTimeout \"10\"\nReadThreads \"50\"\nWriteThreads" +
47 "\"50\"\n\n#Enable plugins:\n\nLoadPlugin cpufreq\nLoadPlugin ipmi\nLoadPlugin" +
48 "turbostat\nLoadPlugin irq\nLoadPlugin memcached\nLoadPlugin memory\nLoadPlugin" +
49 "processes\nLoadPlugin load\n"
50 typesCmName = "types-configmap"
51 watchLabels = "app=collectd"
55 one = intstr.FromInt(1)
56 ls, _ = labels.ConvertSelectorToLabelsMap(watchLabels)
57 cgList = &onapv1alpha1.CollectdGlobalList{
58 Items: []onapv1alpha1.CollectdGlobal{},
60 cm = &corev1.ConfigMap{
61 ObjectMeta: metav1.ObjectMeta{
62 Name: "cp-config-map",
66 Data: map[string]string{
70 readonlyCM = &corev1.ConfigMap{
71 ObjectMeta: metav1.ObjectMeta{
72 Name: "cp-config-map-read-only",
76 Data: map[string]string{
80 typesCm = &corev1.ConfigMap{
81 ObjectMeta: metav1.ObjectMeta{
86 Data: map[string]string{
87 "types.db": "types.db data",
90 ds = &appsv1.DaemonSet{
91 ObjectMeta: metav1.ObjectMeta{
96 Spec: appsv1.DaemonSetSpec{
97 Selector: &metav1.LabelSelector{MatchLabels: ls},
98 UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
99 Type: appsv1.RollingUpdateDaemonSetStrategyType,
100 RollingUpdate: &appsv1.RollingUpdateDaemonSet{
101 MaxUnavailable: &one,
104 Template: corev1.PodTemplateSpec{
105 ObjectMeta: metav1.ObjectMeta{
108 Spec: corev1.PodSpec{
109 Containers: []corev1.Container{{Name: "cp-collectd-1", Image: "collectd"}},
115 cp1 = &onapv1alpha1.CollectdPlugin{
116 TypeMeta: metav1.TypeMeta{
117 Kind: "CollectdPlugin",
118 APIVersion: "onap.org/v1alpha1",
120 ObjectMeta: metav1.ObjectMeta{
122 Namespace: namespace,
124 Spec: onapv1alpha1.CollectdPluginSpec{
126 PluginConf: "<Plugin cpu>\n" +
127 "ReportByCpu true\n" +
128 "ReportByState true\n" +
129 "ValuesPercentage true\n" +
134 delCp1 = &onapv1alpha1.CollectdPlugin{
135 TypeMeta: metav1.TypeMeta{
136 Kind: "CollectdPlugin",
137 APIVersion: "onap.org/v1alpha1",
139 ObjectMeta: metav1.ObjectMeta{
141 Namespace: namespace,
142 DeletionTimestamp: &metav1.Time{
145 Finalizers: []string{
146 utils.CollectdFinalizer,
149 Spec: onapv1alpha1.CollectdPluginSpec{
151 PluginConf: "<Plugin cpu>\n" +
152 "ReportByCpu true\n" +
153 "ReportByState true\n" +
154 "ValuesPercentage true\n" +
159 cp2 = &onapv1alpha1.CollectdPlugin{
160 ObjectMeta: metav1.ObjectMeta{
161 Name: "write_prometheus",
162 Namespace: namespace,
164 Spec: onapv1alpha1.CollectdPluginSpec{
166 PluginConf: "<Plugin write_prometheus>\n" +
172 cpList = &onapv1alpha1.CollectdPluginList{
173 Items: []onapv1alpha1.CollectdPlugin{},
177 func TestReconcileCollectdPlugin_Reconcile(t *testing.T) {
178 logf.SetLogger(logf.ZapLogger(true))
180 os.Setenv("WATCH_LABELS", watchLabels)
184 objs []runtime.Object
185 want reconcile.Result
190 name: "CollectdPlugin Reconcile No CR",
191 objs: getObjs(nil, []runtime.Object{cm, ds}),
192 want: reconcile.Result{Requeue: false},
196 name: "CollectdPlugin Add new CR cp1",
197 objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{cm, ds}),
198 want: reconcile.Result{Requeue: false},
202 name: "CollectdPlugin Delete CR cp1",
203 objs: getObjs([]onapv1alpha1.CollectdPlugin{*delCp1}, []runtime.Object{cm, ds}),
204 want: reconcile.Result{Requeue: false},
208 name: "CollectdPlugin Add new CR No configMap",
209 objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{ds}),
210 want: reconcile.Result{Requeue: false},
215 name: "CollectdPlugin Add new CR no DaemonSet",
216 objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp1}, []runtime.Object{cm}),
217 want: reconcile.Result{Requeue: false},
222 name: "CollectdPlugin Add new CR cp2",
223 objs: getObjs([]onapv1alpha1.CollectdPlugin{*cp2}, []runtime.Object{cm, ds}),
224 want: reconcile.Result{Requeue: false},
228 for _, tt := range tests {
229 t.Run(tt.name, func(t *testing.T) {
233 if r := recover(); r == nil {
234 t.Errorf("The code did not panic")
236 t.Log("Successful Panic")
240 // Objects to track in the fake client.
243 // Register operator types with the runtime scheme.
245 s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, cp1, cpList, cgList)
247 // Create a fake client to mock API calls
248 fc1 := fake.NewFakeClient(objs...)
249 rcp := &ReconcileCollectdPlugin{client: fc1, scheme: s}
250 req := reconcile.Request{
251 NamespacedName: types.NamespacedName{
252 Namespace: namespace,
256 got, err := rcp.Reconcile(req)
258 t.Fatalf("reconcile: (%v)", err)
260 assert.Equal(t, tt.want, got)
266 func TestUpdateStatus(t *testing.T) {
267 // Set the logger to development mode for verbose logs.
268 logf.SetLogger(logf.ZapLogger(true))
270 os.Setenv("WATCH_LABELS", watchLabels)
272 testCases := []struct {
274 cp *onapv1alpha1.CollectdPlugin
276 expectedStatus string
280 name: "Update Status of New CR",
281 cp: getNewCPWithStatus(cp1, onapv1alpha1.Initial),
282 expectedStatus: onapv1alpha1.Created,
286 name: "Update Initial state to Created",
287 cp: getNewCPWithStatus(cp1, onapv1alpha1.Created),
288 expectedStatus: onapv1alpha1.Created,
292 name: "Update Created state - No Pods",
293 cp: getNewCPWithStatus(cp1, onapv1alpha1.Created),
294 expectedStatus: onapv1alpha1.Created,
298 name: "Update Created state to Enabled",
299 cp: getNewCPWithStatus(cp1, onapv1alpha1.Created),
301 expectedStatus: onapv1alpha1.Enabled,
305 req := reconcile.Request{
306 NamespacedName: types.NamespacedName{
307 Namespace: namespace,
312 for _, testCase := range testCases {
313 t.Run(testCase.name, func(t *testing.T) {
314 // Objects to track in the fake client.
315 objs := []runtime.Object{
318 if testCase.createPods {
320 ObjectMeta: metav1.ObjectMeta{
321 Namespace: testCase.cp.Namespace,
322 Name: "cp-collectd-abcde",
325 Spec: corev1.PodSpec{
326 Containers: []corev1.Container{
334 objs = append(objs, runtime.Object(pods))
336 // Register operator types with the runtime scheme.
338 s.AddKnownTypes(onapv1alpha1.SchemeGroupVersion, testCase.cp)
340 // Create a fake client to mock API calls
341 fc1 := fake.NewFakeClient(objs...)
342 rcp := &ReconcileCollectdPlugin{client: fc1, scheme: s}
344 err := rcp.updateStatus(testCase.cp)
345 assert.Equal(t, testCase.expectedError, err)
346 // Fetch the CollectdGlobal instance
347 actual := &onapv1alpha1.CollectdPlugin{}
348 err = fc1.Get(context.TODO(), req.NamespacedName, actual)
349 assert.Equal(t, testCase.expectedStatus, actual.Status.Status)
350 if testCase.createPods {
351 assert.Equal(t, []string{"cp-collectd-abcde"}, actual.Status.CollectdAgents)
357 func getNewCPWithStatus(cp *onapv1alpha1.CollectdPlugin, status string) *onapv1alpha1.CollectdPlugin {
358 cpTemp := cp.DeepCopy()
359 cpTemp.Status.Status = status
363 func getObjs(cp []onapv1alpha1.CollectdPlugin, objs []runtime.Object) []runtime.Object {
364 cpL := cpList.DeepCopy()
366 items := append(cpL.Items, cp...)
368 objs = append(objs, cpL)