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 }