github.com/swisspost/terratest@v0.0.0-20230214120104-7ec6de2e1ae0/modules/helm/install_test.go (about)

     1  //go:build kubeall || helm
     2  // +build kubeall helm
     3  
     4  // NOTE: we have build tags to differentiate kubernetes tests from non-kubernetes tests, and further differentiate helm
     5  // tests. This is done because minikube is heavy and can interfere with docker related tests in terratest. Similarly,
     6  // helm can overload the minikube system and thus interfere with the other kubernetes tests. To avoid overloading the
     7  // system, we run the kubernetes tests and helm tests separately from the others.
     8  
     9  package helm
    10  
    11  import (
    12  	"crypto/tls"
    13  	"fmt"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  
    20  	http_helper "github.com/gruntwork-io/terratest/modules/http-helper"
    21  	"github.com/gruntwork-io/terratest/modules/k8s"
    22  	"github.com/gruntwork-io/terratest/modules/random"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  const (
    27  	remoteChartSource  = "https://charts.bitnami.com/bitnami"
    28  	remoteChartName    = "nginx"
    29  	remoteChartVersion = "13.2.23"
    30  )
    31  
    32  // Test that we can install a remote chart (e.g bitnami/nginx)
    33  func TestRemoteChartInstall(t *testing.T) {
    34  	t.Parallel()
    35  
    36  	namespaceName := fmt.Sprintf(
    37  		"%s-%s",
    38  		strings.ToLower(t.Name()),
    39  		strings.ToLower(random.UniqueId()),
    40  	)
    41  
    42  	// Use default kubectl options to create a new namespace for this test, and then update the namespace for kubectl
    43  	kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName)
    44  
    45  	defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)
    46  	k8s.CreateNamespace(t, kubectlOptions, namespaceName)
    47  
    48  	// Override service type to node port
    49  	options := &Options{
    50  		KubectlOptions: kubectlOptions,
    51  		SetValues: map[string]string{
    52  			"service.type": "NodePort",
    53  		},
    54  	}
    55  
    56  	// Add the stable repo under a random name so as not to touch existing repo configs
    57  	uniqueName := strings.ToLower(fmt.Sprintf("terratest-%s", random.UniqueId()))
    58  	defer RemoveRepo(t, options, uniqueName)
    59  	AddRepo(t, options, uniqueName, remoteChartSource)
    60  	helmChart := fmt.Sprintf("%s/%s", uniqueName, remoteChartName)
    61  
    62  	// Generate a unique release name so we can defer the delete before installing
    63  	releaseName := fmt.Sprintf(
    64  		"%s-%s",
    65  		remoteChartName, strings.ToLower(random.UniqueId()),
    66  	)
    67  	defer Delete(t, options, releaseName, true)
    68  
    69  	// Test if helm.install will return an error if the chart version is incorrect
    70  	options.Version = "notValidVersion.0.0.0"
    71  	require.Error(t, InstallE(t, options, helmChart, releaseName))
    72  
    73  	// Fix chart version and retry install
    74  	options.Version = remoteChartVersion
    75  	// Test that passing extra arguments doesn't error, by changing default timeout
    76  	options.ExtraArgs = map[string][]string{"install": []string{"--timeout", "5m1s"}}
    77  	options.ExtraArgs["delete"] = []string{"--timeout", "5m1s"}
    78  	require.NoError(t, InstallE(t, options, helmChart, releaseName))
    79  	waitForRemoteChartPods(t, kubectlOptions, releaseName, 1)
    80  
    81  	// Verify service is accessible. Wait for it to become available and then hit the endpoint.
    82  	serviceName := releaseName
    83  	k8s.WaitUntilServiceAvailable(t, kubectlOptions, serviceName, 10, 1*time.Second)
    84  	service := k8s.GetService(t, kubectlOptions, serviceName)
    85  	endpoint := k8s.GetServiceEndpoint(t, kubectlOptions, service, 80)
    86  
    87  	// Setup a TLS configuration to submit with the helper, a blank struct is acceptable
    88  	tlsConfig := tls.Config{}
    89  
    90  	http_helper.HttpGetWithRetryWithCustomValidation(
    91  		t,
    92  		fmt.Sprintf("http://%s", endpoint),
    93  		&tlsConfig,
    94  		30,
    95  		10*time.Second,
    96  		func(statusCode int, body string) bool {
    97  			return statusCode == 200
    98  		},
    99  	)
   100  }
   101  
   102  func waitForRemoteChartPods(t *testing.T, kubectlOptions *k8s.KubectlOptions, releaseName string, podCount int) {
   103  	// Get pod and wait for it to be avaialable
   104  	// To get the pod, we need to filter it using the labels that the helm chart creates
   105  	filters := metav1.ListOptions{
   106  		LabelSelector: fmt.Sprintf(
   107  			"app.kubernetes.io/name=%s,app.kubernetes.io/instance=%s",
   108  			remoteChartName, releaseName,
   109  		),
   110  	}
   111  	k8s.WaitUntilNumPodsCreated(t, kubectlOptions, filters, podCount, 30, 10*time.Second)
   112  	pods := k8s.ListPods(t, kubectlOptions, filters)
   113  	for _, pod := range pods {
   114  		k8s.WaitUntilPodAvailable(t, kubectlOptions, pod.Name, 30, 10*time.Second)
   115  	}
   116  }