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  })