github.com/dhaiducek/policy-generator-plugin@v1.99.99/internal/patches_test.go (about) 1 // Copyright Contributors to the Open Cluster Management project 2 package internal 3 4 import ( 5 "fmt" 6 "strings" 7 "testing" 8 9 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 10 ) 11 12 func createExConfigMap(name string) *map[string]interface{} { 13 return &map[string]interface{}{ 14 "apiVersion": "v1", 15 "kind": "ConfigMap", 16 "metadata": map[string]interface{}{ 17 "name": name, 18 "namespace": "default", 19 }, 20 "data": map[string]string{ 21 "game.properties": "enemies=goldfish", 22 "ui.properties": "color.good=neon-green", 23 }, 24 } 25 } 26 27 func TestValidate(t *testing.T) { 28 t.Parallel() 29 30 manifests := []map[string]interface{}{} 31 manifests = append( 32 manifests, *createExConfigMap("configmap1"), *createExConfigMap("configmap2"), 33 ) 34 patches := []map[string]interface{}{ 35 { 36 "apiVersion": "v1", 37 "kind": "ConfigMap", 38 "metadata": map[string]interface{}{ 39 "name": "configmap2", 40 "namespace": "default", 41 "labels": map[string]string{ 42 "chandler": "bing", 43 }, 44 }, 45 }, 46 } 47 48 patcher := manifestPatcher{manifests: manifests, patches: patches} 49 err := patcher.Validate() 50 51 assertEqual(t, err, nil) 52 } 53 54 func TestValidateDefaults(t *testing.T) { 55 t.Parallel() 56 57 manifests := []map[string]interface{}{*createExConfigMap("configmap1")} 58 patches := []map[string]interface{}{ 59 { 60 "metadata": map[string]interface{}{ 61 "labels": map[string]string{ 62 "chandler": "bing", 63 }, 64 }, 65 }, 66 } 67 68 patcher := manifestPatcher{manifests: manifests, patches: patches} 69 err := patcher.Validate() 70 71 assertEqual(t, err, nil) 72 } 73 74 func TestValidateNoManifests(t *testing.T) { 75 t.Parallel() 76 77 patcher := manifestPatcher{ 78 manifests: []map[string]interface{}{}, patches: []map[string]interface{}{}, 79 } 80 err := patcher.Validate() 81 82 assertEqual(t, err.Error(), "there must be one or more manifests") 83 } 84 85 func TestValidateManifestMissingData(t *testing.T) { 86 t.Parallel() 87 88 tests := []struct{ missingFields []string }{ 89 {missingFields: []string{"apiVersion"}}, 90 {missingFields: []string{"kind"}}, 91 {missingFields: []string{"metadata", "name"}}, 92 } 93 94 for _, test := range tests { 95 test := test 96 name := fmt.Sprintf("manifest missing %s", strings.Join(test.missingFields, ".")) 97 98 t.Run( 99 name, 100 func(t *testing.T) { 101 t.Parallel() 102 configmap := *createExConfigMap("configmap1") 103 err := unstructured.SetNestedField(configmap, "", test.missingFields...) 104 if err != nil { 105 t.Fatal(err.Error()) 106 } 107 manifests := []map[string]interface{}{configmap} 108 109 patcher := manifestPatcher{manifests: manifests, patches: []map[string]interface{}{}} 110 err = patcher.Validate() 111 112 expected := fmt.Sprintf( 113 `all manifests must have the "%s" field set to a non-empty string`, 114 strings.Join(test.missingFields, "."), 115 ) 116 assertEqual(t, err.Error(), expected) 117 }, 118 ) 119 } 120 } 121 122 func TestValidatePatchMissingData(t *testing.T) { 123 t.Parallel() 124 125 tests := []struct{ missingFields []string }{ 126 {missingFields: []string{"apiVersion"}}, 127 {missingFields: []string{"kind"}}, 128 {missingFields: []string{"metadata", "name"}}, 129 } 130 131 for _, test := range tests { 132 test := test 133 name := fmt.Sprintf("patch missing %s", strings.Join(test.missingFields, ".")) 134 135 t.Run( 136 name, 137 func(t *testing.T) { 138 t.Parallel() 139 140 manifests := []map[string]interface{}{ 141 *createExConfigMap("configmap1"), *createExConfigMap("configmap2"), 142 } 143 144 patch := map[string]interface{}{ 145 "apiVersion": "v1", 146 "kind": "ConfigMap", 147 "metadata": map[string]interface{}{ 148 "name": "configmap2", 149 "namespace": "default", 150 "labels": map[string]string{ 151 "chandler": "bing", 152 }, 153 }, 154 } 155 err := unstructured.SetNestedField(patch, "", test.missingFields...) 156 if err != nil { 157 t.Fatal(err.Error()) 158 } 159 patches := []map[string]interface{}{patch} 160 161 patcher := manifestPatcher{manifests: manifests, patches: patches} 162 err = patcher.Validate() 163 164 expected := fmt.Sprintf( 165 `patches must have the "%s" field set to a non-empty string when there is `+ 166 "more than one manifest it can apply to", 167 strings.Join(test.missingFields, "."), 168 ) 169 assertEqual(t, err.Error(), expected) 170 }, 171 ) 172 } 173 } 174 175 func TestValidatePatchInvalidSingleManifest(t *testing.T) { 176 t.Parallel() 177 178 tests := []struct{ invalidFields []string }{ 179 {invalidFields: []string{"apiVersion"}}, 180 } 181 182 for _, test := range tests { 183 test := test 184 name := fmt.Sprintf("patch invalid %s", strings.Join(test.invalidFields, ".")) 185 186 t.Run( 187 name, 188 func(t *testing.T) { 189 t.Parallel() 190 191 manifests := []map[string]interface{}{*createExConfigMap("configmap1")} 192 patch := map[string]interface{}{ 193 "apiVersion": "v1", 194 "kind": "ConfigMap", 195 "metadata": map[string]interface{}{ 196 "name": "configmap2", 197 "namespace": "default", 198 "labels": map[string]string{ 199 "chandler": "bing", 200 }, 201 }, 202 } 203 err := unstructured.SetNestedField(patch, true, test.invalidFields...) 204 if err != nil { 205 t.Fatal(err.Error()) 206 } 207 patches := []map[string]interface{}{patch} 208 209 patcher := manifestPatcher{manifests: manifests, patches: patches} 210 err = patcher.Validate() 211 212 invalidFieldsStr := strings.Join(test.invalidFields, ".") 213 expected := fmt.Sprintf( 214 `failed to retrieve the "%s" field from the manifest of name `+ 215 `"configmap1" and kind "ConfigMap": .%s accessor error: true is of the type `+ 216 `bool, expected string`, 217 invalidFieldsStr, 218 invalidFieldsStr, 219 ) 220 assertEqual(t, err.Error(), expected) 221 }, 222 ) 223 } 224 } 225 226 func TestApplyPatches(t *testing.T) { 227 t.Parallel() 228 229 manifests := []map[string]interface{}{} 230 manifests = append( 231 manifests, *createExConfigMap("configmap1"), *createExConfigMap("configmap2"), 232 ) 233 patches := []map[string]interface{}{ 234 { 235 "apiVersion": "v1", 236 "kind": "ConfigMap", 237 "metadata": map[string]interface{}{ 238 "name": "configmap2", 239 "namespace": "default", 240 "labels": map[string]string{ 241 "chandler": "bing", 242 }, 243 }, 244 }, 245 } 246 247 patcher := manifestPatcher{manifests: manifests, patches: patches} 248 patchedManifests, err := patcher.ApplyPatches() 249 250 assertEqual(t, err, nil) 251 252 patchedManifest1 := patchedManifests[0] 253 _, found, _ := unstructured.NestedStringMap(patchedManifest1, "metadata", "labels") 254 255 assertEqual(t, found, false) 256 257 patchedManifest2 := patchedManifests[1] 258 labels, found, _ := unstructured.NestedStringMap(patchedManifest2, "metadata", "labels") 259 260 assertEqual(t, found, true) 261 262 expectedLabels := map[string]string{"chandler": "bing"} 263 264 assertReflectEqual(t, labels, expectedLabels) 265 } 266 267 func TestApplyPatchesInvalidPatch(t *testing.T) { 268 t.Parallel() 269 270 manifests := []map[string]interface{}{} 271 manifests = append( 272 manifests, *createExConfigMap("configmap1"), *createExConfigMap("configmap2"), 273 ) 274 patches := []map[string]interface{}{ 275 { 276 "apiVersion": "v1", 277 "kind": "ToasterOven", 278 "metadata": map[string]interface{}{ 279 "name": "configmap2", 280 "namespace": "default", 281 "labels": map[string]string{ 282 "chandler": "bing", 283 }, 284 }, 285 }, 286 } 287 288 patcher := manifestPatcher{manifests: manifests, patches: patches} 289 _, err := patcher.ApplyPatches() 290 291 expected := "failed to apply the patch(es) to the manifest(s) using Kustomize: no matches " + 292 "for Id ToasterOven.v1.[noGrp]/configmap2.default; failed to find unique target for patch " + 293 "ToasterOven.v1.[noGrp]/configmap2.default" 294 assertEqual(t, err.Error(), expected) 295 }