github.com/verrazzano/verrazzano@v1.7.1/application-operator/controllers/template/template_test.go (about) 1 // Copyright (c) 2021, 2022, 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 template 5 6 import ( 7 "encoding/json" 8 asserts "github.com/stretchr/testify/assert" 9 k8sapps "k8s.io/api/apps/v1" 10 k8score "k8s.io/api/core/v1" 11 k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 13 "k8s.io/apimachinery/pkg/runtime" 14 "k8s.io/apimachinery/pkg/runtime/schema" 15 "sigs.k8s.io/controller-runtime/pkg/client" 16 "sigs.k8s.io/controller-runtime/pkg/client/fake" 17 "testing" 18 ) 19 20 type Workload struct { 21 Name string 22 } 23 type Profile struct { 24 Name string 25 } 26 27 // TestPopulateFromKubeResources tests whether a template can be populated with the values from a configmap and secret 28 // GIVEN that a template processor referencing a configmap and secret in the same namespace 29 // WHEN the processor executes 30 // THEN the resulting string should be populated with values from the config map and secret 31 func TestPopulateFromKubeResources(t *testing.T) { 32 c := getTestClient() 33 templateText := `data: 34 template: 35 - value1: "{{configmap "testNamespace" "testConfigMap" "value1"}}" 36 - value2: "{{configmap "testNamespace" "testConfigMap" "value2"}}" 37 - secret: "{{secret "testNamespace" "someSecret" "secret1"}}" 38 ` 39 expectedOutput := `data: 40 template: 41 - value1: "This is the string associated with value1" 42 - value2: "This is the string associated with value2" 43 - secret: "totallySecretValue" 44 ` 45 tp := NewProcessor(c, templateText) 46 output, err := tp.Process(nil) 47 asserts.NoError(t, err, "error executing template processing for config map values") 48 asserts.Equal(t, expectedOutput, output) 49 } 50 51 // TestPopulateFromStructs tests whether a template can be populated with the values from a provided structs 52 // GIVEN that a template processor referencing multiple structs 53 // WHEN the processor executes 54 // THEN the resulting string should be populated with values from the structs provided as inputs 55 func TestPopulateFromStructs(t *testing.T) { 56 c := getTestClient() 57 inputs := map[string]interface{}{ 58 "workload": Workload{Name: "Workload1"}, 59 "profile": Profile{Name: "Profile1"}, 60 } 61 templateText := `data: 62 template: 63 - workload: "{{.workload.Name}}" 64 - profile: "{{.profile.Name}}" 65 ` 66 expectedOutput := `data: 67 template: 68 - workload: "Workload1" 69 - profile: "Profile1" 70 ` 71 tp := NewProcessor(c, templateText) 72 output, err := tp.Process(inputs) 73 asserts.NoError(t, err, "error executing template processing for config map values") 74 asserts.Equal(t, expectedOutput, output) 75 } 76 77 // TestPopulateFromStructsAndResources tests whether a template can be populated with the values from provided structs and kube resources 78 // GIVEN that a template processor referencing multiple sources 79 // WHEN the processor executes 80 // THEN the resulting string should be populated with values from the sources indicated 81 func TestPopulateFromStructsAndResources(t *testing.T) { 82 c := getTestClient() 83 inputs := map[string]interface{}{ 84 "workload": Workload{Name: "Workload1"}, 85 "profile": Profile{Name: "Profile1"}, 86 } 87 templateText := `data: 88 template: 89 - value1: "{{configmap "testNamespace" "testConfigMap" "value1"}}" 90 - value2: "{{configmap "testNamespace" "testConfigMap" "value2"}}" 91 - secret: "{{secret "testNamespace" "someSecret" "secret1"}}" 92 - workload: "{{.workload.Name}}" 93 - profile: "{{.profile.Name}}" 94 ` 95 expectedOutput := `data: 96 template: 97 - value1: "This is the string associated with value1" 98 - value2: "This is the string associated with value2" 99 - secret: "totallySecretValue" 100 - workload: "Workload1" 101 - profile: "Profile1" 102 ` 103 tp := NewProcessor(c, templateText) 104 output, err := tp.Process(inputs) 105 asserts.NoError(t, err, "error executing template processing for config map values") 106 asserts.Equal(t, expectedOutput, output) 107 } 108 109 // TestPopulateFromUnstructured tests populating a template from an Unstructured input 110 // GIVEN a template that references a nested value within an Unstructured 111 // WHEN the processor executes 112 // THEN the resulting string should be populated from the Unstructured's values 113 func TestPopulateFromUnstructured(t *testing.T) { 114 assert := asserts.New(t) 115 c := getTestClient() 116 workload, err := convertToUnstructured( 117 k8sapps.Deployment{ 118 ObjectMeta: k8smeta.ObjectMeta{ 119 Namespace: "test-namespace-name", 120 Name: "test-workload-name", 121 }}) 122 assert.NoError(err, "error converting resource to unstructured") 123 inputs := map[string]interface{}{ 124 "workload": workload.Object, 125 } 126 templateText := `<{{.workload.metadata.namespace}}/{{.workload.metadata.name}}>` 127 expectedOutput := `<test-namespace-name/test-workload-name>` 128 tp := NewProcessor(c, templateText) 129 actualOutput, err := tp.Process(inputs) 130 assert.NoError(err, "error processing template") 131 assert.Equal(expectedOutput, actualOutput, "expected template to be populated correctly from unstructured") 132 } 133 134 // TestPopulateFromGet tests populating a template from values obtained from a fetched resource 135 // GIVEN a template that references a function to get a resource 136 // WHEN the processor executes 137 // THEN the resulting string should be populated from the resources values 138 func TestPopulateFromGet(t *testing.T) { 139 assert := asserts.New(t) 140 c := getTestClient() 141 templateText := `{{$cm := get "v1" "ConfigMap" "testNamespace" "testConfigMap"}}<{{$cm.metadata.name}}>` 142 expectedOutput := `<testConfigMap>` 143 tp := NewProcessor(c, templateText) 144 actualOutput, err := tp.Process(nil) 145 assert.NoError(err, "error processing template") 146 assert.Equal(expectedOutput, actualOutput, "expected template to be populated correctly from unstructured") 147 } 148 149 // getTestClient returns a controller/kube client with references to simple secret and configmap 150 func getTestClient() client.Client { 151 c := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects( 152 &k8score.Secret{ 153 ObjectMeta: k8smeta.ObjectMeta{ 154 Name: "someSecret", 155 Namespace: "testNamespace", 156 }, 157 Data: map[string][]byte{ 158 "secret1": []byte("totallySecretValue"), 159 }, 160 }, 161 &k8score.ConfigMap{ 162 ObjectMeta: k8smeta.ObjectMeta{ 163 Name: "testConfigMap", 164 Namespace: "testNamespace", 165 }, 166 Data: map[string]string{ 167 "value1": "This is the string associated with value1", 168 "value2": "This is the string associated with value2", 169 }, 170 }).Build() 171 return c 172 } 173 174 func newScheme() *runtime.Scheme { 175 scheme := runtime.NewScheme() 176 k8score.SchemeBuilder.AddToScheme(scheme) 177 scheme.AddKnownTypes(schema.GroupVersion{ 178 Version: "v1", 179 }, &k8score.Secret{}, &k8score.ConfigMap{}) 180 181 return scheme 182 } 183 184 // convertToUnstructured converts an object to an Unstructured version 185 // object - The object to convert to Unstructured 186 func convertToUnstructured(object interface{}) (unstructured.Unstructured, error) { 187 jbytes, err := json.Marshal(object) 188 if err != nil { 189 return unstructured.Unstructured{}, err 190 } 191 var u map[string]interface{} 192 json.Unmarshal(jbytes, &u) 193 return unstructured.Unstructured{Object: u}, nil 194 }