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  }