github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/update/availability/availability_test.go (about) 1 // Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package availability 5 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 "strings" 11 "time" 12 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 "github.com/verrazzano/verrazzano/pkg/k8sutil" 16 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 17 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 18 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 ) 20 21 const ( 22 pollingInterval = 10 * time.Second 23 timeout = 10 * time.Minute 24 deployName = "rancher" 25 deployNamespace = "cattle-system" 26 ) 27 28 var ( 29 t = framework.NewTestFramework("availability") 30 clientset = k8sutil.GetKubernetesClientsetOrDie() 31 ) 32 33 var beforeSuite = t.BeforeSuiteFunc(func() {}) 34 var _ = BeforeSuite(beforeSuite) 35 36 var _ = t.Describe("Status", func() { 37 // If a component is taken offline, the number of unavailable components should increase by 1 38 // When that component is put back online, the number of unavailable components should be 0 39 t.It("dynamically scales availability", func() { 40 t.Logs.Info("Should be 0 unavailable components when the test begins") 41 hasUnavailableComponents(0) 42 t.Logs.Infof("Scale down target deployment %s/%s", deployNamespace, deployName) 43 scaleDeployment(deployName, deployNamespace, 0) 44 t.Logs.Info("After the health check updates the status, 1 component should be unavailable") 45 hasUnavailableComponents(1) 46 t.Logs.Infof("Scale up the target deployment %s/%s", deployNamespace, deployName) 47 scaleDeployment(deployName, deployNamespace, 3) 48 t.Logs.Info("After the health check updates the status, all components should be available") 49 hasUnavailableComponents(0) 50 }) 51 }) 52 53 func scaleDeployment(name, namespace string, replicas int32) { 54 Eventually(func() bool { 55 deploy, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 56 if err != nil { 57 t.Logs.Errorf("Error fetching deployment: %v", err) 58 return false 59 } 60 deploy.Spec.Replicas = &replicas 61 _, err = clientset.AppsV1().Deployments(namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}) 62 return err == nil 63 }).WithPolling(pollingInterval).WithTimeout(timeout).Should(BeTrue()) 64 } 65 66 func hasUnavailableComponents(numUnavailable int) { 67 Eventually(func() bool { 68 verrazzano, err := pkg.GetVerrazzano() 69 if err != nil { 70 t.Logs.Errorf("Error fetching Verrazzano: %v", err) 71 return false 72 } 73 isMet, err := availabilityCriteriaMet(verrazzano.Status.Available, numUnavailable) 74 if err != nil { 75 t.Logs.Errorf("Error finding availability criteria: %v", err) 76 return false 77 } 78 return isMet 79 }).WithPolling(pollingInterval).WithTimeout(timeout).Should(BeTrue()) 80 } 81 82 func availabilityCriteriaMet(availability *string, numUnavailable int) (bool, error) { 83 if availability == nil { 84 return false, nil 85 } 86 // availability is of the form "x/y" where x is components available, y is components enabled 87 lValue, rValue, err := parseAvailability(*availability) 88 if err != nil { 89 return false, err 90 } 91 return lValue+numUnavailable == rValue, nil 92 } 93 94 func parseAvailability(availability string) (int, int, error) { 95 const invalid = -1 96 split := strings.Split(availability, "/") 97 if len(split) != 2 { 98 return invalid, invalid, fmt.Errorf("availability should have to numeric terms, got %s", availability) 99 } 100 lValue, err := strconv.Atoi(split[0]) 101 if err != nil { 102 return invalid, invalid, err 103 } 104 rValue, err := strconv.Atoi(split[1]) 105 if err != nil { 106 return invalid, invalid, err 107 } 108 return lValue, rValue, nil 109 }