github.com/koderover/helm@v2.17.0+incompatible/pkg/tiller/hooks_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tiller 18 19 import ( 20 "bytes" 21 "reflect" 22 "testing" 23 "text/template" 24 25 "github.com/ghodss/yaml" 26 27 "k8s.io/helm/pkg/chartutil" 28 "k8s.io/helm/pkg/proto/hapi/release" 29 util "k8s.io/helm/pkg/releaseutil" 30 ) 31 32 func TestSortManifests(t *testing.T) { 33 34 data := []struct { 35 name []string 36 path string 37 kind []string 38 hooks map[string][]release.Hook_Event 39 manifest string 40 }{ 41 { 42 name: []string{"first"}, 43 path: "one", 44 kind: []string{"Job"}, 45 hooks: map[string][]release.Hook_Event{"first": {release.Hook_PRE_INSTALL}}, 46 manifest: `apiVersion: v1 47 kind: Job 48 metadata: 49 name: first 50 labels: 51 doesnot: matter 52 annotations: 53 "helm.sh/hook": pre-install 54 `, 55 }, 56 { 57 name: []string{"second"}, 58 path: "two", 59 kind: []string{"ReplicaSet"}, 60 hooks: map[string][]release.Hook_Event{"second": {release.Hook_POST_INSTALL}}, 61 manifest: `kind: ReplicaSet 62 apiVersion: v1beta1 63 metadata: 64 name: second 65 annotations: 66 "helm.sh/hook": post-install 67 `, 68 }, { 69 name: []string{"third"}, 70 path: "three", 71 kind: []string{"ReplicaSet"}, 72 hooks: map[string][]release.Hook_Event{"third": nil}, 73 manifest: `kind: ReplicaSet 74 apiVersion: v1beta1 75 metadata: 76 name: third 77 annotations: 78 "helm.sh/hook": no-such-hook 79 `, 80 }, { 81 name: []string{"fourth"}, 82 path: "four", 83 kind: []string{"Pod"}, 84 hooks: map[string][]release.Hook_Event{"fourth": nil}, 85 manifest: `kind: Pod 86 apiVersion: v1 87 metadata: 88 name: fourth 89 annotations: 90 nothing: here`, 91 }, { 92 name: []string{"fifth"}, 93 path: "five", 94 kind: []string{"ReplicaSet"}, 95 hooks: map[string][]release.Hook_Event{"fifth": {release.Hook_POST_DELETE, release.Hook_POST_INSTALL}}, 96 manifest: `kind: ReplicaSet 97 apiVersion: v1beta1 98 metadata: 99 name: fifth 100 annotations: 101 "helm.sh/hook": post-delete, post-install 102 `, 103 }, { 104 // Regression test: files with an underscore in the base name should be skipped. 105 name: []string{"sixth"}, 106 path: "six/_six", 107 kind: []string{"ReplicaSet"}, 108 hooks: map[string][]release.Hook_Event{"sixth": nil}, 109 manifest: `invalid manifest`, // This will fail if partial is not skipped. 110 }, { 111 // Regression test: files with no content should be skipped. 112 name: []string{"seventh"}, 113 path: "seven", 114 kind: []string{"ReplicaSet"}, 115 hooks: map[string][]release.Hook_Event{"seventh": nil}, 116 manifest: "", 117 }, 118 { 119 name: []string{"eighth", "example-test"}, 120 path: "eight", 121 kind: []string{"ConfigMap", "Pod"}, 122 hooks: map[string][]release.Hook_Event{"eighth": nil, "example-test": {release.Hook_RELEASE_TEST_SUCCESS}}, 123 manifest: `kind: ConfigMap 124 apiVersion: v1 125 metadata: 126 name: eighth 127 data: 128 name: value 129 --- 130 apiVersion: v1 131 kind: Pod 132 metadata: 133 name: example-test 134 annotations: 135 "helm.sh/hook": test-success 136 `, 137 }, 138 } 139 140 manifests := make(map[string]string, len(data)) 141 for _, o := range data { 142 manifests[o.path] = o.manifest 143 } 144 145 hs, generic, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder) 146 if err != nil { 147 t.Fatalf("Unexpected error: %s", err) 148 } 149 150 // This test will fail if 'six' or 'seven' was added. 151 if len(generic) != 2 { 152 t.Errorf("Expected 2 generic manifests, got %d", len(generic)) 153 } 154 155 if len(hs) != 4 { 156 t.Errorf("Expected 4 hooks, got %d", len(hs)) 157 } 158 159 for _, out := range hs { 160 found := false 161 for _, expect := range data { 162 if out.Path == expect.path { 163 found = true 164 if out.Path != expect.path { 165 t.Errorf("Expected path %s, got %s", expect.path, out.Path) 166 } 167 nameFound := false 168 for _, expectedName := range expect.name { 169 if out.Name == expectedName { 170 nameFound = true 171 } 172 } 173 if !nameFound { 174 t.Errorf("Got unexpected name %s", out.Name) 175 } 176 kindFound := false 177 for _, expectedKind := range expect.kind { 178 if out.Kind == expectedKind { 179 kindFound = true 180 } 181 } 182 if !kindFound { 183 t.Errorf("Got unexpected kind %s", out.Kind) 184 } 185 186 expectedHooks := expect.hooks[out.Name] 187 if !reflect.DeepEqual(expectedHooks, out.Events) { 188 t.Errorf("expected events: %v but got: %v", expectedHooks, out.Events) 189 } 190 191 } 192 } 193 if !found { 194 t.Errorf("Result not found: %v", out) 195 } 196 } 197 198 // Verify the sort order 199 sorted := []Manifest{} 200 for _, s := range data { 201 manifests := util.SplitManifests(s.manifest) 202 203 for _, m := range manifests { 204 var sh util.SimpleHead 205 err := yaml.Unmarshal([]byte(m), &sh) 206 if err != nil { 207 // This is expected for manifests that are corrupt or empty. 208 t.Log(err) 209 continue 210 } 211 212 name := sh.Metadata.Name 213 214 //only keep track of non-hook manifests 215 if err == nil && s.hooks[name] == nil { 216 another := Manifest{ 217 Content: m, 218 Name: name, 219 Head: &sh, 220 } 221 sorted = append(sorted, another) 222 } 223 } 224 } 225 226 sorted = sortByKind(sorted, InstallOrder) 227 for i, m := range generic { 228 if m.Content != sorted[i].Content { 229 t.Errorf("Expected %q, got %q", m.Content, sorted[i].Content) 230 } 231 } 232 } 233 234 var manifestTemplate = ` 235 apiVersion: apiextensions.k8s.io/v1beta1 236 kind: CustomResourceDefinition 237 metadata: 238 name: example.com 239 labels: 240 app: example-crd 241 annotations: 242 helm.sh/hook: crd-install 243 {{- if .HookDeletePolicy}} 244 {{ .HookDeletePolicy }} 245 {{- end }} 246 {{- if .HookDeleteTimeout}} 247 {{ .HookDeleteTimeout }} 248 {{- end }} 249 spec: 250 group: example.com 251 version: v1alpha1 252 names: 253 kind: example 254 plural: examples 255 scope: Cluster 256 ` 257 258 type manifestTemplateData struct { 259 HookDeletePolicy, HookDeleteTimeout string 260 } 261 262 func TestSortManifestsHookDeletion(t *testing.T) { 263 testCases := map[string]struct { 264 templateData manifestTemplateData 265 hasDeletePolicy bool 266 deletePolicy release.Hook_DeletePolicy 267 deleteTimeout int64 268 }{ 269 "No delete policy": { 270 templateData: manifestTemplateData{}, 271 hasDeletePolicy: false, 272 deletePolicy: release.Hook_BEFORE_HOOK_CREATION, 273 deleteTimeout: 0, 274 }, 275 "Delete policy, no delete timeout": { 276 templateData: manifestTemplateData{ 277 HookDeletePolicy: "helm.sh/hook-delete-policy: before-hook-creation", 278 }, 279 hasDeletePolicy: true, 280 deletePolicy: release.Hook_BEFORE_HOOK_CREATION, 281 deleteTimeout: defaultHookDeleteTimeoutInSeconds, 282 }, 283 "Delete policy and delete timeout": { 284 templateData: manifestTemplateData{ 285 HookDeletePolicy: "helm.sh/hook-delete-policy: hook-succeeded", 286 HookDeleteTimeout: `helm.sh/hook-delete-timeout: "420"`, 287 }, 288 hasDeletePolicy: true, 289 deletePolicy: release.Hook_SUCCEEDED, 290 deleteTimeout: 420, 291 }, 292 } 293 294 for tn, tc := range testCases { 295 t.Run(tn, func(t *testing.T) { 296 tmpl := template.Must(template.New("manifest").Parse(manifestTemplate)) 297 var buf bytes.Buffer 298 err := tmpl.Execute(&buf, tc.templateData) 299 if err != nil { 300 t.Error(err) 301 } 302 303 manifests := map[string]string{ 304 "exampleManifest": buf.String(), 305 } 306 307 hs, _, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder) 308 if err != nil { 309 t.Error(err) 310 } 311 312 if got, want := len(hs), 1; got != want { 313 t.Errorf("expected %d hooks, but got %d", want, got) 314 } 315 hook := hs[0] 316 317 if len(hook.DeletePolicies) == 0 { 318 if tc.hasDeletePolicy { 319 t.Errorf("expected a policy, but got zero") 320 } 321 } else { 322 if !tc.hasDeletePolicy { 323 t.Errorf("expected no delete policies, but got one") 324 } 325 policy := hook.DeletePolicies[0] 326 if got, want := policy, tc.deletePolicy; got != want { 327 t.Errorf("expected delete policy %q, but got %q", want, got) 328 } 329 } 330 331 if got, want := hook.DeleteTimeout, tc.deleteTimeout; got != want { 332 t.Errorf("expected timeout %d, but got %d", want, got) 333 } 334 }) 335 } 336 } 337 338 func TestVersionSet(t *testing.T) { 339 vs := chartutil.NewVersionSet("v1", "v1beta1", "extensions/alpha5", "batch/v1") 340 341 if l := len(vs); l != 4 { 342 t.Errorf("Expected 4, got %d", l) 343 } 344 345 if !vs.Has("extensions/alpha5") { 346 t.Error("No match for alpha5") 347 } 348 349 if vs.Has("nosuch/extension") { 350 t.Error("Found nonexistent extension") 351 } 352 }