github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/util/util_test.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package util 21 22 import ( 23 "context" 24 "fmt" 25 "os" 26 "strings" 27 "time" 28 29 . "github.com/onsi/ginkgo/v2" 30 . "github.com/onsi/gomega" 31 32 "github.com/go-logr/logr" 33 corev1 "k8s.io/api/core/v1" 34 "k8s.io/apimachinery/pkg/api/resource" 35 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 36 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 37 dynamicfakeclient "k8s.io/client-go/dynamic/fake" 38 "k8s.io/client-go/kubernetes/scheme" 39 cmdtesting "k8s.io/kubectl/pkg/cmd/testing" 40 "sigs.k8s.io/controller-runtime/pkg/log" 41 42 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 43 "github.com/1aal/kubeblocks/pkg/cli/testing" 44 "github.com/1aal/kubeblocks/pkg/cli/types" 45 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 46 "github.com/1aal/kubeblocks/pkg/constant" 47 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 48 "github.com/1aal/kubeblocks/test/testdata" 49 ) 50 51 var _ = Describe("util", func() { 52 It("Get home dir", func() { 53 home, err := GetCliHomeDir() 54 Expect(len(home) > 0).Should(BeTrue()) 55 Expect(err == nil).Should(BeTrue()) 56 }) 57 58 It("Get kubeconfig dir", func() { 59 dir := GetKubeconfigDir() 60 Expect(len(dir) > 0).Should(BeTrue()) 61 }) 62 63 It("DoWithRetry", func() { 64 op := func() error { 65 return fmt.Errorf("test DowithRetry") 66 } 67 logger := logr.New(log.NullLogSink{}) 68 Expect(DoWithRetry(context.TODO(), logger, op, &RetryOptions{MaxRetry: 2})).Should(HaveOccurred()) 69 }) 70 71 It("Config path", func() { 72 path := ConfigPath("") 73 Expect(len(path) == 0).Should(BeTrue()) 74 path = ConfigPath("test") 75 Expect(len(path) > 0).Should(BeTrue()) 76 Expect(RemoveConfig("")).Should(HaveOccurred()) 77 }) 78 79 It("Print yaml", func() { 80 obj := &unstructured.Unstructured{ 81 Object: map[string]interface{}{ 82 "apiVersion": "dataprotection.kubeblocks.io/v1alpha1", 83 "kind": "BackupJob", 84 "metadata": map[string]interface{}{ 85 "namespace": "default", 86 "name": "test", 87 }, 88 "spec": map[string]interface{}{ 89 "backupPolicyName": "backup-policy-demo", 90 "backupType": "full", 91 "ttl": "7d", 92 }, 93 }, 94 } 95 Expect(PrintObjYAML(obj)).Should(Succeed()) 96 }) 97 98 It("Print go template", func() { 99 Expect(PrintGoTemplate(os.Stdout, `key: {{.Value}}`, struct { 100 Value string 101 }{"test"})).Should(Succeed()) 102 }) 103 104 It("GetNodeByName", func() { 105 nodes := []*corev1.Node{ 106 { 107 ObjectMeta: metav1.ObjectMeta{ 108 Name: "test", 109 }, 110 }, 111 } 112 113 testFn := func(name string) bool { 114 n := GetNodeByName(nodes, name) 115 if n != nil { 116 return n.Name == name 117 } 118 return false 119 } 120 Expect(testFn("test")).Should(BeTrue()) 121 Expect(testFn("non-exists")).Should(BeFalse()) 122 }) 123 124 It("GetPodStatus", func() { 125 newPod := func(phase corev1.PodPhase) corev1.Pod { 126 return corev1.Pod{ 127 Status: corev1.PodStatus{ 128 Phase: phase, 129 }} 130 } 131 132 var pods []corev1.Pod 133 for _, p := range []corev1.PodPhase{corev1.PodRunning, corev1.PodPending, corev1.PodSucceeded, corev1.PodFailed} { 134 pods = append(pods, newPod(p)) 135 } 136 137 r, w, s, f := GetPodStatus(pods) 138 Expect(r).Should(Equal(1)) 139 Expect(w).Should(Equal(1)) 140 Expect(s).Should(Equal(1)) 141 Expect(f).Should(Equal(1)) 142 }) 143 144 It("TimeFormat", func() { 145 t, _ := time.Parse(time.RFC3339, "2023-01-04T01:00:00.000Z") 146 metav1Time := metav1.Time{Time: t} 147 Expect(TimeFormat(&metav1Time)).Should(Equal("Jan 04,2023 01:00 UTC+0000")) 148 Expect(TimeFormatWithDuration(&metav1Time, time.Minute)).Should(Equal("Jan 04,2023 01:00 UTC+0000")) 149 Expect(TimeFormatWithDuration(&metav1Time, time.Second)).Should(Equal("Jan 04,2023 01:00:00 UTC+0000")) 150 Expect(TimeFormatWithDuration(&metav1Time, time.Millisecond)).Should(Equal("Jan 04,2023 01:00:00.000 UTC+0000")) 151 }) 152 153 It("CheckEmpty", func() { 154 res := "" 155 Expect(CheckEmpty(res)).Should(Equal(types.None)) 156 res = "test" 157 Expect(CheckEmpty(res)).Should(Equal(res)) 158 }) 159 160 It("BuildLabelSelectorByNames", func() { 161 Expect(BuildLabelSelectorByNames("", nil)).Should(Equal("")) 162 163 names := []string{"n1", "n2"} 164 expected := fmt.Sprintf("%s in (%s)", constant.AppInstanceLabelKey, strings.Join(names, ",")) 165 Expect(BuildLabelSelectorByNames("", names)).Should(Equal(expected)) 166 Expect(BuildLabelSelectorByNames("label1", names)).Should(Equal("label1," + expected)) 167 }) 168 169 It("Event utils", func() { 170 objs := SortEventsByLastTimestamp(testing.FakeEvents(), "") 171 Expect(len(*objs)).Should(Equal(2)) 172 firstEvent := (*objs)[0].(*corev1.Event) 173 secondEvent := (*objs)[1].(*corev1.Event) 174 Expect(firstEvent.LastTimestamp.Before(&secondEvent.LastTimestamp)).Should(BeTrue()) 175 Expect(GetEventTimeStr(firstEvent)).Should(ContainSubstring("Jan 04,2023")) 176 }) 177 178 It("Others", func() { 179 if os.Getenv("TEST_GET_PUBLIC_IP") != "" { 180 _, err := GetPublicIP() 181 Expect(err).ShouldNot(HaveOccurred()) 182 } 183 Expect(MakeSSHKeyPair("", "")).Should(HaveOccurred()) 184 Expect(SetKubeConfig("test")).Should(Succeed()) 185 Expect(NewFactory()).ShouldNot(BeNil()) 186 187 By("resource is empty") 188 res := resource.Quantity{} 189 Expect(ResourceIsEmpty(&res)).Should(BeTrue()) 190 res.Set(20) 191 Expect(ResourceIsEmpty(&res)).Should(BeFalse()) 192 193 By("GVRToString") 194 Expect(len(GVRToString(types.ClusterGVR())) > 0).Should(BeTrue()) 195 }) 196 197 It("IsSupportReconfigureParams", func() { 198 const ( 199 ccName = "mysql_cc" 200 testNS = "default" 201 ) 202 203 configConstraintObj := testapps.NewCustomizedObj("resources/mysql-config-constraint.yaml", 204 &appsv1alpha1.ConfigConstraint{}, testapps.WithNamespacedName(ccName, ""), func(cc *appsv1alpha1.ConfigConstraint) { 205 if ccContext, err := testdata.GetTestDataFileContent("/cue_testdata/mysql_for_cli.cue"); err == nil { 206 cc.Spec.ConfigurationSchema = &appsv1alpha1.CustomParametersValidation{ 207 CUE: string(ccContext), 208 } 209 } 210 }) 211 badcaseCCObject := configConstraintObj.DeepCopy() 212 badcaseCCObject.Spec.CfgSchemaTopLevelName = "badcase" 213 badcaseCCObject.SetName("badcase") 214 215 tf := cmdtesting.NewTestFactory().WithNamespace(testNS) 216 defer tf.Cleanup() 217 218 Expect(appsv1alpha1.AddToScheme(scheme.Scheme)).Should(Succeed()) 219 mockClient := dynamicfakeclient.NewSimpleDynamicClientWithCustomListKinds(scheme.Scheme, nil, configConstraintObj, badcaseCCObject) 220 configSpec := appsv1alpha1.ComponentConfigSpec{ 221 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 222 Name: "for_test", 223 TemplateRef: ccName, 224 VolumeName: "config", 225 }, 226 ConfigConstraintRef: ccName, 227 } 228 229 type args struct { 230 configSpec appsv1alpha1.ComponentConfigSpec 231 updatedParams map[string]string 232 } 233 tests := []struct { 234 name string 235 args args 236 expected bool 237 err error 238 }{{ 239 name: "normal test", 240 args: args{ 241 configSpec: configSpec, 242 updatedParams: testapps.WithMap("automatic_sp_privileges", "OFF", "innodb_autoinc_lock_mode", "1"), 243 }, 244 expected: true, 245 }, { 246 name: "not match test", 247 args: args{ 248 configSpec: configSpec, 249 updatedParams: testapps.WithMap("not_exist_field", "1"), 250 }, 251 expected: false, 252 }, { 253 name: "badcase test", 254 args: args{ 255 configSpec: appsv1alpha1.ComponentConfigSpec{ 256 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 257 Name: "for_test", 258 TemplateRef: ccName, 259 VolumeName: "config", 260 }, 261 ConfigConstraintRef: "badcase", 262 }, 263 updatedParams: testapps.WithMap("automatic_sp_privileges", "1"), 264 }, 265 expected: false, 266 err: cfgcore.MakeError("field not found:"), 267 }} 268 269 for _, tt := range tests { 270 ret, err := IsSupportReconfigureParams(tt.args.configSpec, cfgcore.FromStringPointerMap(tt.args.updatedParams), mockClient) 271 Expect(ret).Should(BeEquivalentTo(tt.expected)) 272 Expect(err != nil).Should(BeEquivalentTo(tt.err != nil)) 273 if err != nil { 274 Expect(err.Error()).Should(ContainSubstring(tt.err.Error())) 275 } 276 } 277 }) 278 279 It("get IP location", func() { 280 _, _ = GetIPLocation() 281 }) 282 283 It("get helm chart repo url", func() { 284 Expect(GetHelmChartRepoURL()).ShouldNot(BeEmpty()) 285 }) 286 287 It("new OpsRequest for Reconfiguring ", func() { 288 Expect(NewOpsRequestForReconfiguring("logs", "test", "cluster")).ShouldNot(BeNil()) 289 }) 290 291 It("convert obj to unstructured ", func() { 292 unstructuredObj, err := ConvertObjToUnstructured(testing.FakeConfigMap("cm-test", testing.Namespace, map[string]string{"fake": "fake"})) 293 Expect(err).ShouldNot(HaveOccurred()) 294 Expect(unstructuredObj.Object).Should(HaveLen(4)) 295 296 _, err = ConvertObjToUnstructured(struct{ name string }{name: "test"}) 297 Expect(err).Should(HaveOccurred()) 298 }) 299 300 It("test build toleration", func() { 301 validRaws := []string{"dev=true:NoSchedule,large:NoSchedule"} 302 tolerations, err := BuildTolerations(validRaws) 303 Expect(err).Should(BeNil()) 304 Expect(len(tolerations)).Should(Equal(2)) 305 306 // optimize these codes 307 invalidRaws := []string{"dev=true"} 308 _, err = BuildTolerations(invalidRaws) 309 Expect(err).Should(HaveOccurred()) 310 }) 311 312 It("test build node affinity", func() { 313 nodeLabels := make(map[string]string) 314 Expect(BuildNodeAffinity(nodeLabels)).Should(BeNil()) 315 316 nodeLabels["testNodeLabels"] = "testNodeLabels" 317 Expect(BuildNodeAffinity(nodeLabels)).ShouldNot(BeNil()) 318 }) 319 320 It("test build pod affinity", func() { 321 topologyKey := "testTopologyKey" 322 323 topologyKeys := []string{topologyKey} 324 podAntiAffinityStrategy := "testPodAntiAffinityStrategy" 325 podAntiAffinity := BuildPodAntiAffinity(podAntiAffinityStrategy, topologyKeys) 326 Expect(podAntiAffinity).ShouldNot(BeNil()) 327 Expect(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution[0].Weight).ShouldNot(BeNil()) 328 Expect(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution[0].PodAffinityTerm.TopologyKey).Should(Equal(topologyKey)) 329 }) 330 })