github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/util/util_test.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package util_test 20 21 import ( 22 "errors" 23 24 "github.com/IBM-Blockchain/fabric-operator/pkg/util" 25 . "github.com/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 corev1 "k8s.io/api/core/v1" 28 "k8s.io/apimachinery/pkg/api/resource" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 ) 31 32 var _ = Describe("Util", func() { 33 34 Context("Convert yaml file to json", func() { 35 It("returns an error if file does not exist", func() { 36 _, err := util.ConvertYamlFileToJson("fake.yaml") 37 Expect(err).To(HaveOccurred()) 38 Expect(err.Error()).To(ContainSubstring("no such file")) 39 }) 40 41 It("returns an error if yaml file is not properly formatted", func() { 42 _, err := util.ConvertYamlFileToJson("testdata/bad.yaml") 43 Expect(err).To(HaveOccurred()) 44 }) 45 46 It("return a byte arrary if the file exists and is a valid yaml file", func() { 47 bytes, err := util.ConvertYamlFileToJson("../../definitions/peer/pvc.yaml") 48 Expect(err).NotTo(HaveOccurred()) 49 Expect(len(bytes)).NotTo(Equal(0)) 50 }) 51 }) 52 53 Context("GetPVCFromFile", func() { 54 It("returns an error if config is incorrectly defined", func() { 55 _, err := util.GetPVCFromFile("testdata/invalid_kind.yaml") 56 Expect(err).To(HaveOccurred()) 57 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 58 }) 59 60 It("reads file with PVC configuration and unmarshals into a struct", func() { 61 pvc, err := util.GetPVCFromFile("../../definitions/peer/pvc.yaml") 62 Expect(err).NotTo(HaveOccurred()) 63 Expect(pvc).NotTo(BeNil()) 64 }) 65 }) 66 67 Context("GetDeploymentFromFile", func() { 68 It("returns an error if config is incorrectly defined", func() { 69 _, err := util.GetDeploymentFromFile("testdata/invalid_kind.yaml") 70 Expect(err).To(HaveOccurred()) 71 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 72 }) 73 74 It("reads file with Deployment configuration and unmarshals into a struct", func() { 75 dep, err := util.GetDeploymentFromFile("../../definitions/peer/deployment.yaml") 76 Expect(err).NotTo(HaveOccurred()) 77 Expect(dep).NotTo(BeNil()) 78 }) 79 }) 80 81 Context("GetServiceFromFile", func() { 82 It("returns an error if config is incorrectly defined", func() { 83 _, err := util.GetServiceFromFile("testdata/invalid_kind.yaml") 84 Expect(err).To(HaveOccurred()) 85 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 86 }) 87 88 It("reads file with Service configuration and unmarshals into a struct", func() { 89 srvc, err := util.GetServiceFromFile("../../definitions/peer/service.yaml") 90 Expect(err).NotTo(HaveOccurred()) 91 Expect(srvc).NotTo(BeNil()) 92 }) 93 }) 94 95 Context("GetSecretFromFile", func() { 96 It("returns an error if config is incorrectly defined", func() { 97 _, err := util.GetSecretFromFile("testdata/invalid_kind.yaml") 98 Expect(err).To(HaveOccurred()) 99 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 100 }) 101 It("reads file with Service configuration and unmarshals into a struct", func() { 102 srvc, err := util.GetSecretFromFile("../../testdata/secret.yaml") 103 Expect(err).NotTo(HaveOccurred()) 104 Expect(srvc).NotTo(BeNil()) 105 }) 106 }) 107 108 Context("GetIngressFromFile", func() { 109 It("returns an error if config is incorrectly defined", func() { 110 _, err := util.GetIngressFromFile("testdata/invalid_kind.yaml") 111 Expect(err).To(HaveOccurred()) 112 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 113 }) 114 }) 115 116 Context("GetIngressv1beta1FromFile", func() { 117 It("returns an error if config is incorrectly defined", func() { 118 _, err := util.GetIngressv1beta1FromFile("testdata/invalid_kind.yaml") 119 Expect(err).To(HaveOccurred()) 120 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 121 }) 122 }) 123 124 Context("GetRoleFromFile", func() { 125 It("returns an error if config is incorrectly defined", func() { 126 _, err := util.GetRoleFromFile("testdata/invalid_kind.yaml") 127 Expect(err).To(HaveOccurred()) 128 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 129 }) 130 131 It("reads file with Role configuration and unmarshals into a struct", func() { 132 srvc, err := util.GetRoleFromFile("../../definitions/peer/role.yaml") 133 Expect(err).NotTo(HaveOccurred()) 134 Expect(srvc).NotTo(BeNil()) 135 }) 136 }) 137 138 Context("GetRoleBindingFromFile", func() { 139 It("returns an error if config is incorrectly defined", func() { 140 _, err := util.GetRoleBindingFromFile("testdata/invalid_kind.yaml") 141 Expect(err).To(HaveOccurred()) 142 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 143 }) 144 145 It("reads file with RoleBinding configuration and unmarshals into a struct", func() { 146 srvc, err := util.GetRoleBindingFromFile("../../definitions/peer/rolebinding.yaml") 147 Expect(err).NotTo(HaveOccurred()) 148 Expect(srvc).NotTo(BeNil()) 149 }) 150 }) 151 152 Context("GetServiceAccountFromFile", func() { 153 It("returns an error if config is incorrectly defined", func() { 154 _, err := util.GetServiceAccountFromFile("testdata/invalid_kind.yaml") 155 Expect(err).To(HaveOccurred()) 156 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 157 }) 158 159 It("reads file with SA configuration and unmarshals into a struct", func() { 160 srvc, err := util.GetServiceAccountFromFile("../../definitions/peer/serviceaccount.yaml") 161 Expect(err).NotTo(HaveOccurred()) 162 Expect(srvc).NotTo(BeNil()) 163 }) 164 }) 165 166 Context("GetCRDFromFile", func() { 167 It("returns an error if config is incorrectly defined", func() { 168 _, err := util.GetCRDFromFile("testdata/invalid_kind.yaml") 169 Expect(err).To(HaveOccurred()) 170 Expect(err.Error()).To(ContainSubstring("cannot unmarshal")) 171 }) 172 173 It("reads file with CRD configuration and unmarshals into a struct", func() { 174 srvc, err := util.GetCRDFromFile("../../config/crd/bases/ibp.com_ibpcas.yaml") 175 Expect(err).NotTo(HaveOccurred()) 176 Expect(srvc).NotTo(BeNil()) 177 }) 178 }) 179 180 Context("GetResourcePatch", func() { 181 It("return resource struct that retains values that have not been modified and contains new values for if values are updated", func() { 182 183 resourceList := make(corev1.ResourceList) 184 resourceList[corev1.ResourceCPU] = resource.MustParse("0.5") 185 resourceList[corev1.ResourceMemory] = resource.MustParse("5Gi") 186 resourceList[corev1.ResourceEphemeralStorage] = resource.MustParse("1Gi") 187 188 current := &corev1.ResourceRequirements{ 189 Requests: resourceList, 190 } 191 192 resourceList[corev1.ResourceCPU] = resource.MustParse("0.7") 193 new := &corev1.ResourceRequirements{ 194 Requests: resourceList, 195 } 196 197 patched, err := util.GetResourcePatch(current, new) 198 Expect(err).NotTo(HaveOccurred()) 199 200 cpu := patched.Requests[corev1.ResourceCPU] 201 Expect(cpu.String()).To(Equal("700m")) 202 memory := patched.Requests[corev1.ResourceMemory] 203 Expect(memory.String()).To(Equal("5Gi")) 204 ephermalStorage := patched.Requests[corev1.ResourceEphemeralStorage] 205 Expect(ephermalStorage.String()).To(Equal("1Gi")) 206 }) 207 }) 208 209 Context("already exists error", func() { 210 It("returns error if it is not an already exists error", func() { 211 err := util.IgnoreAlreadyExistError(errors.New("failed to create resource")) 212 Expect(err).To(HaveOccurred()) 213 Expect(err.Error()).To(Equal("failed to create resource")) 214 }) 215 216 It("does not return error if an already exists error", func() { 217 err := util.IgnoreAlreadyExistError(errors.New("resource already exists")) 218 Expect(err).NotTo(HaveOccurred()) 219 }) 220 }) 221 222 Context("update existing env var", func() { 223 var envs []corev1.EnvVar 224 225 BeforeEach(func() { 226 env := corev1.EnvVar{ 227 Name: "GENERATE_GENESIS", 228 Value: "false", 229 } 230 envs = append(envs, env) 231 }) 232 233 It("updates env var if found in slice", func() { 234 newEnvs := util.UpdateEnvVar("GENERATE_GENESIS", "true", envs) 235 Expect(newEnvs[0].Value).To(Equal("true")) 236 }) 237 }) 238 239 Context("env exists", func() { 240 var envs []corev1.EnvVar 241 242 BeforeEach(func() { 243 env := corev1.EnvVar{ 244 Name: "GENERATE_GENESIS", 245 Value: "false", 246 } 247 envs = append(envs, env) 248 249 env = corev1.EnvVar{ 250 Name: "TEST_NAME", 251 Value: "false", 252 } 253 envs = append(envs, env) 254 }) 255 256 It("returns true if found in slice", func() { 257 exists := util.EnvExists(envs, "TEST_NAME") 258 Expect(exists).To(Equal(true)) 259 }) 260 261 It("returns false if not found in slice", func() { 262 exists := util.EnvExists(envs, "FAKE_NAME") 263 Expect(exists).To(Equal(false)) 264 }) 265 }) 266 267 Context("replaces (updates) env if diff", func() { 268 var envs []corev1.EnvVar 269 270 BeforeEach(func() { 271 env := corev1.EnvVar{ 272 Name: "GENERATE_GENESIS", 273 Value: "false", 274 } 275 envs = append(envs, env) 276 277 env = corev1.EnvVar{ 278 Name: "TEST_NAME", 279 Value: "false", 280 } 281 envs = append(envs, env) 282 }) 283 284 It("returns env with updated replaced value", func() { 285 key := "TEST_NAME" 286 replace := "true" 287 newEnvs, _ := util.ReplaceEnvIfDiff(envs, key, replace) 288 Expect(newEnvs[1].Value).To(Equal("true")) 289 }) 290 }) 291 292 Context("Resource Validation", func() { 293 It("returns an error if controller handling the request is reconciling a resource of different type", func() { 294 typemeta := metav1.TypeMeta{ 295 Kind: "NOTIBPCA", 296 } 297 maxNameLength := 50 298 err := util.ValidationChecks(typemeta, metav1.ObjectMeta{}, "IBPCA", &maxNameLength) 299 Expect(err).To(HaveOccurred()) 300 Expect(err.Error()).To(ContainSubstring("not an IBPCA kind resource, please check to make sure there are no name collisions across resources")) 301 }) 302 303 It("returns an error if the instance name is greater than maxNameLength", func() { 304 typemeta := metav1.TypeMeta{ 305 Kind: "IBPCA", 306 } 307 objectmeta := metav1.ObjectMeta{ 308 Name: "012345678901234567890123456789", 309 } 310 maxNameLength := 25 311 err := util.ValidationChecks(typemeta, objectmeta, "IBPCA", &maxNameLength) 312 Expect(err).To(HaveOccurred()) 313 Expect(err.Error()).To(ContainSubstring("is too long, the name must be less than or equal to ")) 314 }) 315 316 It("returns an error if the instance name is greater than default name length", func() { 317 typemeta := metav1.TypeMeta{ 318 Kind: "IBPCA", 319 } 320 objectmeta := metav1.ObjectMeta{ 321 Name: "0123456789012345678901234567890123", 322 } 323 err := util.ValidationChecks(typemeta, objectmeta, "IBPCA", nil) 324 Expect(err).To(HaveOccurred()) 325 Expect(err.Error()).To(ContainSubstring("is too long, the name must be less than or equal to")) 326 }) 327 }) 328 329 Context("HSM proxy endpoint validation", func() { 330 It("returns no error for a valid endpoint", func() { 331 err := util.ValidateHSMProxyURL("tcp://0.0.0.0:2348") 332 Expect(err).NotTo(HaveOccurred()) 333 }) 334 335 It("returns no error for a valid TLS endpoint", func() { 336 err := util.ValidateHSMProxyURL("tls://0.0.0.0:2348") 337 Expect(err).NotTo(HaveOccurred()) 338 }) 339 340 It("returns an error for incomplete endpoint", func() { 341 err := util.ValidateHSMProxyURL("tcp://0.0.0.0") 342 Expect(err).To(HaveOccurred()) 343 Expect(err.Error()).To(Equal("must specify both IP address and port")) 344 }) 345 346 It("returns an error for missing port", func() { 347 err := util.ValidateHSMProxyURL("tcp://0.0.0.0:") 348 Expect(err).To(HaveOccurred()) 349 Expect(err.Error()).To(Equal("missing port")) 350 }) 351 352 It("returns an error for missing IP address", func() { 353 err := util.ValidateHSMProxyURL("tcp://:2348") 354 Expect(err).To(HaveOccurred()) 355 Expect(err.Error()).To(Equal("missing IP address")) 356 }) 357 358 It("returns an error for invalid scheme", func() { 359 err := util.ValidateHSMProxyURL("http://0.0.0.0:8888") 360 Expect(err).To(HaveOccurred()) 361 Expect(err.Error()).To(Equal("unsupported scheme 'http', only tcp and tls are supported")) 362 }) 363 }) 364 365 Context("append image pull secret if missing", func() { 366 var ( 367 pullSecrets []corev1.LocalObjectReference 368 ) 369 370 BeforeEach(func() { 371 pullSecrets = []corev1.LocalObjectReference{ 372 corev1.LocalObjectReference{ 373 Name: "pullsecret1", 374 }, 375 } 376 }) 377 378 It("appends new image pull secret", func() { 379 new := corev1.LocalObjectReference{Name: "pullsecret2"} 380 pullSecrets := util.AppendImagePullSecretIfMissing(pullSecrets, new) 381 Expect(len(pullSecrets)).To(Equal(2)) 382 Expect(pullSecrets[1]).To(Equal(new)) 383 }) 384 385 It("does not append existing image pull secret", func() { 386 new := corev1.LocalObjectReference{Name: "pullsecret1"} 387 pullSecrets := util.AppendImagePullSecretIfMissing(pullSecrets, new) 388 Expect(len(pullSecrets)).To(Equal(1)) 389 Expect(pullSecrets[0].Name).To(Equal("pullsecret1")) 390 }) 391 392 It("does not appen blank image pull secret", func() { 393 new := corev1.LocalObjectReference{} 394 pullSecrets := util.AppendImagePullSecretIfMissing(pullSecrets, new) 395 Expect(len(pullSecrets)).To(Equal(1)) 396 Expect(pullSecrets[0].Name).To(Equal("pullsecret1")) 397 }) 398 }) 399 })