From 0582f64ac205cd1b0387c444acc9974259647e31 Mon Sep 17 00:00:00 2001 From: pulkit_jain <42600268+jainpulkit22@users.noreply.github.com> Date: Tue, 15 Nov 2022 19:54:07 +0530 Subject: [PATCH] Add unit tests for pkg/antctl/raw/set package (#4307) Added unit tests to improve the UT coverage for pkg/antctl/raw/set package. Signed-off-by: Pulkit Jain --- pkg/antctl/raw/set/command.go | 4 +- .../command.go | 17 +- .../raw/set/flowaggregator/command_test.go | 299 ++++++++++++++++++ 3 files changed, 315 insertions(+), 5 deletions(-) rename pkg/antctl/raw/set/{flow-aggregator => flowaggregator}/command.go (95%) create mode 100644 pkg/antctl/raw/set/flowaggregator/command_test.go diff --git a/pkg/antctl/raw/set/command.go b/pkg/antctl/raw/set/command.go index 00efd5a80c2..43b5e87f3cf 100644 --- a/pkg/antctl/raw/set/command.go +++ b/pkg/antctl/raw/set/command.go @@ -17,7 +17,7 @@ package set import ( "github.com/spf13/cobra" - flow_aggregator "antrea.io/antrea/pkg/antctl/raw/set/flow-aggregator" + flowaggregator "antrea.io/antrea/pkg/antctl/raw/set/flowaggregator" ) var SetCmd = &cobra.Command{ @@ -26,5 +26,5 @@ var SetCmd = &cobra.Command{ } func init() { - SetCmd.AddCommand(flow_aggregator.NewFlowAggregatorSetCommand()) + SetCmd.AddCommand(flowaggregator.NewFlowAggregatorSetCommand()) } diff --git a/pkg/antctl/raw/set/flow-aggregator/command.go b/pkg/antctl/raw/set/flowaggregator/command.go similarity index 95% rename from pkg/antctl/raw/set/flow-aggregator/command.go rename to pkg/antctl/raw/set/flowaggregator/command.go index 5d3bf0a23de..880f795d02b 100644 --- a/pkg/antctl/raw/set/flow-aggregator/command.go +++ b/pkg/antctl/raw/set/flowaggregator/command.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package flow_aggregator +package flowaggregator import ( "context" @@ -39,6 +39,8 @@ type FlowAggregatorConfigMutator func(c *flowaggregatorconfig.FlowAggregatorConf var mutators map[string]FlowAggregatorConfigMutator +var getClients = getk8sClient + var example = strings.Trim(` Enable ClickHouse $ antctl set flow-aggregator clickHouse.enable=true @@ -97,12 +99,17 @@ func NewFlowAggregatorSetCommand() *cobra.Command { return Command } -func updateRunE(cmd *cobra.Command, args []string) error { +func getk8sClient(cmd *cobra.Command) (kubernetes.Interface, error) { kubeconfig, err := raw.ResolveKubeconfig(cmd) if err != nil { - return err + return nil, err } k8sClient, _, err := raw.SetupClients(kubeconfig) + return k8sClient, err +} + +func updateRunE(cmd *cobra.Command, args []string) error { + k8sClient, err := getClients(cmd) if err != nil { return fmt.Errorf("failed to create clientset: %w", err) } @@ -133,6 +140,10 @@ func updateRunE(cmd *cobra.Command, args []string) error { if err != nil { return err } + + if configMap.Data == nil { + configMap.Data = make(map[string]string) + } configMap.Data["flow-aggregator.conf"] = string(b) if _, err := k8sClient.CoreV1().ConfigMaps(os.Getenv("POD_NAMESPACE")).Update(context.TODO(), configMap, metav1.UpdateOptions{}); err != nil { return err diff --git a/pkg/antctl/raw/set/flowaggregator/command_test.go b/pkg/antctl/raw/set/flowaggregator/command_test.go new file mode 100644 index 00000000000..b48656a5227 --- /dev/null +++ b/pkg/antctl/raw/set/flowaggregator/command_test.go @@ -0,0 +1,299 @@ +// Copyright 2022 Antrea 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. + +package flowaggregator + +import ( + "context" + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" +) + +func TestGetk8sClient(t *testing.T) { + tcs := []struct { + name string + fakeConfigs []byte + expectedErr string + }{ + { + name: "invalid kubeconfig", + fakeConfigs: []byte(`apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: data + server: https://localhost + name: fake-cluster +contexts: +- context: + cluster: fake-cluster + user: user-id + name: fake-cluster +current-context: fake-cluster +kind: Config`), + expectedErr: "failed to create K8s clientset: unable to load root certificates: unable to parse bytes as PEM block", + }, + { + name: "valid kubeconf", + fakeConfigs: []byte(`apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJTHJac3Z6ZFQ3ekF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBNE1qSXdNakl6TXpkYUZ3MHlNekE0TWpJd01qSXpNemxhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTB4N2JEd2NqSzN3VjRGSzkKYUtrd0FUdjVoT2NsbHhUSEI1ejFUbHZJV3pmdTNYNjZtaWkxUE04ODI1dTArdDRRdisxUVRIRHFzUkNvWFA1awpuNGNWZkxkeTlad25uN01uSDExVTRsRWRoeXBrdlZsc0RmajlBdWh3WHBZVE82eE5kM2o2Y3BIZGNMOW9PbGw2CkowcGU2RzBleHpTSHMvbHRUZXlyalRGbXM2Sm5zSWV6T2lHRmhZOTJCbDBmZ1krb2p6MFEwM2cvcE5QZUszcGMKK05wTWh4eG1UY1lVNzlaZVRqV1JPYTFQSituNk1SMEhDbW0xQk5QNmdwWmozbGtWSktkZnBEYmovWHYvQWNkVQpab3E5Ym95aGNDUCtiYmgyaWVtaTc0bnZqZ1BUTkVDZWU2a3ZHY3VNaXRKUkdvWjBxbFpZbXZDaWdEeGlSTnBNClBPa1dud0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JSc2VoZXVkM0l5VWRNdkhhRS9YU3MrOFErLwpiVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBcmg4UFRadFgvWjlHVzlMYmxZZ1FWWE04VlRrWEtGSEpTZldOCkJLNXo2NWNWdGN2cFZ0WDZNTlppTFhuYkFzQ0JPY1RqejBJRlphYkNNUkZzYmdYbEVqV0ZuRE5abzBMVHFTZUcKQ2RqTWljK0JzbmFGUThZOXJ5TTVxZ0RhQzNWQkdTSXVscklXeGxPYmRmUEpWRnpUaVNTcmJBR1Z3Uk5sQlpmYgpYOXBlRlpNNmNFNUhTOE5RTmNoZkh2SWhGSUVuR2YxOUx2enp0WGUzQWwwb3hYNjdRKzhyWXd0Tm56dS9xM29BCmJIN1dsNld5ODVYNS90RWlQcWU0ZU1GalRDME9tR2NHZ2lQdU90NjlIejAwV2hvaWNYYWpma1FZOHNKMk5Uc1cKdUcxbWZqb0tTdUN0OC9BRmhPNURlaHZ3eFNIQU12eG1VQUJYL294bU1DNzdwV0VnRWc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + server: https://localhost + name: fake-cluster +contexts: +- context: + cluster: fake-cluster + user: user-id + name: fake-cluster +current-context: fake-cluster +kind: Config`), + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + cmd := NewFlowAggregatorSetCommand() + fakeKubeconfig, err := os.CreateTemp("", "fakeKubeconfig") + if err != nil { + t.Fatalf("Failed to create temp kubeconfig: %v", err) + } + defer os.Remove(fakeKubeconfig.Name()) + fakeKubeconfig.Write(tc.fakeConfigs) + cmd.Flags().String("kubeconfig", fakeKubeconfig.Name(), "path of kubeconfig") + _, err = getk8sClient(cmd) + if tc.expectedErr == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.expectedErr) + } + }) + } +} + +func TestUpdateRunE(t *testing.T) { + fakeConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testConfigMap", + Namespace: "flow-aggregator", + }, + } + + k8sClient := fake.NewSimpleClientset(fakeConfigMap) + tcs := []struct { + name string + configMapName string + podNamespace string + args []string + expectedErr string + expectedOutput map[string]string + }{ + { + name: "valid ConfigMap and nil args", + configMapName: "testConfigMap", + podNamespace: "flow-aggregator", + expectedOutput: map[string]string{"flow-aggregator.conf": "{}\n"}, + }, + { + name: "invalid ConfigMap and nil args", + configMapName: "", + podNamespace: "flow-aggregator", + expectedErr: "failed to locate flow-aggregator-config ConfigMap volume", + }, + { + name: "valid ConfigMap and valid args", + configMapName: "testConfigMap", + podNamespace: "flow-aggregator", + args: []string{"clickHouse.enable=true"}, + expectedOutput: map[string]string{"flow-aggregator.conf": "clickHouse:\n enable: true\n"}, + }, + { + name: "valid ConfigMap and invalid args", + configMapName: "testConfigMap", + podNamespace: "flow-aggregator", + args: []string{"clickhouse=true"}, + expectedErr: "unknown configuration parameter, please check antctl set flow-aggregator -h", + }, + { + name: "valid ConfigMap and invalid args syntax", + configMapName: "testConfigMap", + podNamespace: "flow-aggregator", + args: []string{"clickhouse.enable=true clickhopuse.debug=true"}, + expectedErr: "query should contain exactly one '='", + }, + { + name: "wrong Pod Namespace", + configMapName: "testConfigMap", + podNamespace: "flow-visibility", + expectedErr: "request namespace does not match object namespace", + }, + } + + getClients = func(cmd *cobra.Command) (kubernetes.Interface, error) { + return k8sClient, nil + } + defer func() { + getClients = getk8sClient + }() + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + cmd := NewFlowAggregatorSetCommand() + os.Setenv("POD_NAMESPACE", tc.podNamespace) + os.Setenv("FA_CONFIG_MAP_NAME", tc.configMapName) + defer os.Unsetenv("POD_NAMESPACE") + defer os.Unsetenv("FA_CONFIG_MAP_NAME") + err := updateRunE(cmd, tc.args) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + } else { + assert.NoError(t, err) + cm, _ := k8sClient.CoreV1().ConfigMaps(os.Getenv("POD_NAMESPACE")).Get(context.TODO(), fakeConfigMap.Name, metav1.GetOptions{}) + assert.Equal(t, tc.expectedOutput, cm.Data) + } + }) + } +} + +func TestSetBoolOrFail(t *testing.T) { + tcs := []struct { + name string + value string + expectedValue bool + expectedErr string + }{ + { + name: "true boolean value", + value: "1", + expectedValue: true, + }, + { + name: "false boolean value", + value: "f", + expectedValue: false, + }, + { + name: "invalid value", + value: "tt", + expectedErr: "invalid syntax", + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + var actualValue bool + err := setBoolOrFail(&actualValue, tc.value) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedValue, actualValue) + } + }) + } +} + +func TestSetStringOrFail(t *testing.T) { + var actualValue string + value := "11mm" + + err := setStringOrFail(&actualValue, value) + assert.NoError(t, err) + assert.Equal(t, value, actualValue) +} + +func TestSetCommitIntervalOrFail(t *testing.T) { + tcs := []struct { + name string + value string + expectedErr string + }{ + { + name: "valid commit interval", + value: "1m25s", + }, + { + name: "very short commit interval", + value: "0.5s", + expectedErr: "commitInterval 500ms is too small: shortest supported interval is", + }, + { + name: "invalid value string", + value: "0.5ss", + expectedErr: "time: unknown unit", + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + var actualValue string + err := setCommitIntervalOrFail(&actualValue, tc.value) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.value, actualValue) + } + }) + } +} + +func TestGetFAConfigMap(t *testing.T) { + fakeConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testConfigMap", + Namespace: "flow-aggregator", + }, + } + + k8sClient := fake.NewSimpleClientset(fakeConfigMap) + tcs := []struct { + name string + configMapName string + expectedErr string + }{ + { + name: "get ConfigMap successfully", + configMapName: "testConfigMap", + }, + { + name: "empty ConfigMap name", + configMapName: "", + expectedErr: "failed to locate flow-aggregator-config ConfigMap volume", + }, + { + name: "non existing ConfigMap", + configMapName: "testConfigMap1", + expectedErr: "failed to get ConfigMap testConfigMap1", + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + cm, err := GetFAConfigMap(k8sClient, tc.configMapName) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + } else { + assert.NoError(t, err) + assert.Equal(t, fakeConfigMap, cm) + } + }) + } +}