github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/test/helm_basic_example_template_test.go (about) 1 // +build kubeall helm 2 3 // **NOTE**: we have build tags to differentiate kubernetes tests from non-kubernetes tests, and further differentiate helm 4 // tests. This is done because minikube is heavy and can interfere with docker related tests in terratest. Similarly, helm 5 // can overload the minikube system and thus interfere with the other kubernetes tests. Specifically, many of the tests 6 // start to fail with `connection refused` errors from `minikube`. To avoid overloading the system, we run the kubernetes 7 // tests and helm tests separately from the others. This may not be necessary if you have a sufficiently powerful machine. 8 // We recommend at least 4 cores and 16GB of RAM if you want to run all the tests together. 9 10 package test 11 12 import ( 13 "path/filepath" 14 "strings" 15 "testing" 16 17 "github.com/stretchr/testify/require" 18 appsv1 "k8s.io/api/apps/v1" 19 20 "github.com/gruntwork-io/terratest/modules/helm" 21 "github.com/gruntwork-io/terratest/modules/k8s" 22 "github.com/gruntwork-io/terratest/modules/logger" 23 "github.com/gruntwork-io/terratest/modules/random" 24 ) 25 26 // This file contains examples of how to use terratest to test helm chart template logic by rendering the templates 27 // using `helm template`, and then reading in the rendered templates. 28 // There are two tests: 29 // - TestHelmBasicExampleTemplateRenderedDeployment: An example of how to read in the rendered object and check the 30 // computed values. 31 // - TestHelmBasicExampleTemplateRequiredTemplateArgs: An example of how to check that the required args are indeed 32 // required for the template to render. 33 34 // An example of how to verify the rendered template object of a Helm Chart given various inputs. 35 func TestHelmBasicExampleTemplateRenderedDeployment(t *testing.T) { 36 t.Parallel() 37 38 // Path to the helm chart we will test 39 helmChartPath, err := filepath.Abs("../examples/helm-basic-example") 40 releaseName := "helm-basic" 41 require.NoError(t, err) 42 43 // Since we aren't deploying any resources, there is no need to setup kubectl authentication or helm home. 44 45 // Set up the namespace; confirm that the template renders the expected value for the namespace. 46 namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) 47 logger.Logf(t, "Namespace: %s\n", namespaceName) 48 49 // Setup the args. For this test, we will set the following input values: 50 // - containerImageRepo=nginx 51 // - containerImageTag=1.15.8 52 options := &helm.Options{ 53 SetValues: map[string]string{ 54 "containerImageRepo": "nginx", 55 "containerImageTag": "1.15.8", 56 }, 57 KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), 58 } 59 60 // Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since 61 // we want to assert that the template renders without any errors. 62 // Additionally, although we know there is only one yaml file in the template, we deliberately path a templateFiles 63 // arg to demonstrate how to select individual templates to render. 64 output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/deployment.yaml"}) 65 66 // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will 67 // ensure the Deployment resource is rendered correctly. 68 var deployment appsv1.Deployment 69 helm.UnmarshalK8SYaml(t, output, &deployment) 70 71 // Verify the namespace matches the expected supplied namespace. 72 require.Equal(t, namespaceName, deployment.Namespace) 73 74 // Finally, we verify the deployment pod template spec is set to the expected container image value 75 expectedContainerImage := "nginx:1.15.8" 76 deploymentContainers := deployment.Spec.Template.Spec.Containers 77 require.Equal(t, len(deploymentContainers), 1) 78 require.Equal(t, deploymentContainers[0].Image, expectedContainerImage) 79 } 80 81 // An example of how to verify required values for a helm chart. 82 func TestHelmBasicExampleTemplateRequiredTemplateArgs(t *testing.T) { 83 t.Parallel() 84 85 // Path to the helm chart we will test 86 helmChartPath, err := filepath.Abs("../examples/helm-basic-example") 87 releaseName := "helm-basic" 88 require.NoError(t, err) 89 90 // Since we aren't deploying any resources, there is no need to setup kubectl authentication, helm home, or 91 // namespaces 92 93 // Here, we use a table driven test to iterate through all the required values as subtests. You can learn more about 94 // go subtests here: https://blog.golang.org/subtests 95 // The struct captures the inputs that we will pass to helm template and a human friendly name so we can identify it 96 // in the test output. In this case, each test case will be a complete values input except for one of the required 97 // values missing, to test that neglecting a required value will cause the template rendering to fail. 98 testCases := []struct { 99 name string 100 values map[string]string 101 }{ 102 { 103 "MissingContainerImageRepo", 104 map[string]string{"containerImageTag": "1.15.8"}, 105 }, 106 { 107 "MissingContainerImageTag", 108 map[string]string{"containerImageRepo": "nginx"}, 109 }, 110 } 111 112 // Now we iterate over each test case and spawn a sub test 113 for _, testCase := range testCases { 114 // Here, we capture the range variable and force it into the scope of this block. If we don't do this, when the 115 // subtest switches contexts (because of t.Parallel), the testCase value will have been updated by the for loop 116 // and will be the next testCase! 117 testCase := testCase 118 119 // The actual sub test spawning. We name the sub test using the human friendly name. Note that we name the sub 120 // test T struct to subT to make it clear which T struct corresponds to which test. However, in most cases you 121 // will not reference the main test T so you can name it the same. 122 t.Run(testCase.name, func(subT *testing.T) { 123 subT.Parallel() 124 125 // Now we try rendering the template, but verify we get an error 126 options := &helm.Options{SetValues: testCase.values} 127 _, err := helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{}) 128 require.Error(t, err) 129 }) 130 } 131 }