1
16
17 package action
18
19 import (
20 "context"
21 "fmt"
22 "io"
23 "os"
24 "path/filepath"
25 "regexp"
26 "runtime"
27 "strings"
28 "testing"
29 "time"
30
31 "github.com/stretchr/testify/assert"
32 "github.com/stretchr/testify/require"
33
34 "helm.sh/helm/v3/internal/test"
35 "helm.sh/helm/v3/pkg/chart"
36 "helm.sh/helm/v3/pkg/chartutil"
37 kubefake "helm.sh/helm/v3/pkg/kube/fake"
38 "helm.sh/helm/v3/pkg/release"
39 "helm.sh/helm/v3/pkg/storage/driver"
40 helmtime "helm.sh/helm/v3/pkg/time"
41 )
42
43 type nameTemplateTestCase struct {
44 tpl string
45 expected string
46 expectedErrorStr string
47 }
48
49 func installAction(t *testing.T) *Install {
50 config := actionConfigFixture(t)
51 instAction := NewInstall(config)
52 instAction.Namespace = "spaced"
53 instAction.ReleaseName = "test-install-release"
54
55 return instAction
56 }
57
58 func TestInstallRelease(t *testing.T) {
59 is := assert.New(t)
60 req := require.New(t)
61
62 instAction := installAction(t)
63 vals := map[string]interface{}{}
64 ctx, done := context.WithCancel(context.Background())
65 res, err := instAction.RunWithContext(ctx, buildChart(), vals)
66 if err != nil {
67 t.Fatalf("Failed install: %s", err)
68 }
69 is.Equal(res.Name, "test-install-release", "Expected release name.")
70 is.Equal(res.Namespace, "spaced")
71
72 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
73 is.NoError(err)
74
75 is.Len(rel.Hooks, 1)
76 is.Equal(rel.Hooks[0].Manifest, manifestWithHook)
77 is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall)
78 is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete")
79
80 is.NotEqual(len(res.Manifest), 0)
81 is.NotEqual(len(rel.Manifest), 0)
82 is.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world")
83 is.Equal(rel.Info.Description, "Install complete")
84
85
86
87 done()
88 time.Sleep(time.Millisecond * 100)
89 lastRelease, err := instAction.cfg.Releases.Last(rel.Name)
90 req.NoError(err)
91 is.Equal(lastRelease.Info.Status, release.StatusDeployed)
92 }
93
94 func TestInstallReleaseWithValues(t *testing.T) {
95 is := assert.New(t)
96 instAction := installAction(t)
97 userVals := map[string]interface{}{
98 "nestedKey": map[string]interface{}{
99 "simpleKey": "simpleValue",
100 },
101 }
102 expectedUserValues := map[string]interface{}{
103 "nestedKey": map[string]interface{}{
104 "simpleKey": "simpleValue",
105 },
106 }
107 res, err := instAction.Run(buildChart(withSampleValues()), userVals)
108 if err != nil {
109 t.Fatalf("Failed install: %s", err)
110 }
111 is.Equal(res.Name, "test-install-release", "Expected release name.")
112 is.Equal(res.Namespace, "spaced")
113
114 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
115 is.NoError(err)
116
117 is.Len(rel.Hooks, 1)
118 is.Equal(rel.Hooks[0].Manifest, manifestWithHook)
119 is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall)
120 is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete")
121
122 is.NotEqual(len(res.Manifest), 0)
123 is.NotEqual(len(rel.Manifest), 0)
124 is.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world")
125 is.Equal("Install complete", rel.Info.Description)
126 is.Equal(expectedUserValues, rel.Config)
127 }
128
129 func TestInstallReleaseClientOnly(t *testing.T) {
130 is := assert.New(t)
131 instAction := installAction(t)
132 instAction.ClientOnly = true
133 instAction.Run(buildChart(), nil)
134
135 is.Equal(instAction.cfg.Capabilities, chartutil.DefaultCapabilities)
136 is.Equal(instAction.cfg.KubeClient, &kubefake.PrintingKubeClient{Out: io.Discard})
137 }
138
139 func TestInstallRelease_NoName(t *testing.T) {
140 instAction := installAction(t)
141 instAction.ReleaseName = ""
142 vals := map[string]interface{}{}
143 _, err := instAction.Run(buildChart(), vals)
144 if err == nil {
145 t.Fatal("expected failure when no name is specified")
146 }
147 assert.Contains(t, err.Error(), "no name provided")
148 }
149
150 func TestInstallRelease_WithNotes(t *testing.T) {
151 is := assert.New(t)
152 instAction := installAction(t)
153 instAction.ReleaseName = "with-notes"
154 vals := map[string]interface{}{}
155 res, err := instAction.Run(buildChart(withNotes("note here")), vals)
156 if err != nil {
157 t.Fatalf("Failed install: %s", err)
158 }
159
160 is.Equal(res.Name, "with-notes")
161 is.Equal(res.Namespace, "spaced")
162
163 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
164 is.NoError(err)
165 is.Len(rel.Hooks, 1)
166 is.Equal(rel.Hooks[0].Manifest, manifestWithHook)
167 is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall)
168 is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete")
169 is.NotEqual(len(res.Manifest), 0)
170 is.NotEqual(len(rel.Manifest), 0)
171 is.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world")
172 is.Equal(rel.Info.Description, "Install complete")
173
174 is.Equal(rel.Info.Notes, "note here")
175 }
176
177 func TestInstallRelease_WithNotesRendered(t *testing.T) {
178 is := assert.New(t)
179 instAction := installAction(t)
180 instAction.ReleaseName = "with-notes"
181 vals := map[string]interface{}{}
182 res, err := instAction.Run(buildChart(withNotes("got-{{.Release.Name}}")), vals)
183 if err != nil {
184 t.Fatalf("Failed install: %s", err)
185 }
186
187 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
188 is.NoError(err)
189
190 expectedNotes := fmt.Sprintf("got-%s", res.Name)
191 is.Equal(expectedNotes, rel.Info.Notes)
192 is.Equal(rel.Info.Description, "Install complete")
193 }
194
195 func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) {
196
197 is := assert.New(t)
198 instAction := installAction(t)
199 instAction.ReleaseName = "with-notes"
200 vals := map[string]interface{}{}
201 res, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals)
202 if err != nil {
203 t.Fatalf("Failed install: %s", err)
204 }
205
206 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
207 is.Equal("with-notes", rel.Name)
208 is.NoError(err)
209 is.Equal("parent", rel.Info.Notes)
210 is.Equal(rel.Info.Description, "Install complete")
211 }
212
213 func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) {
214
215 is := assert.New(t)
216 instAction := installAction(t)
217 instAction.ReleaseName = "with-notes"
218 instAction.SubNotes = true
219 vals := map[string]interface{}{}
220 res, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals)
221 if err != nil {
222 t.Fatalf("Failed install: %s", err)
223 }
224
225 rel, err := instAction.cfg.Releases.Get(res.Name, res.Version)
226 is.Equal("with-notes", rel.Name)
227 is.NoError(err)
228
229 if !strings.Contains(rel.Info.Notes, "parent") && !strings.Contains(rel.Info.Notes, "child") {
230 t.Fatalf("Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes)
231 }
232 is.Equal(rel.Info.Description, "Install complete")
233 }
234
235 func TestInstallRelease_DryRun(t *testing.T) {
236 is := assert.New(t)
237 instAction := installAction(t)
238 instAction.DryRun = true
239 vals := map[string]interface{}{}
240 res, err := instAction.Run(buildChart(withSampleTemplates()), vals)
241 if err != nil {
242 t.Fatalf("Failed install: %s", err)
243 }
244
245 is.Contains(res.Manifest, "---\n# Source: hello/templates/hello\nhello: world")
246 is.Contains(res.Manifest, "---\n# Source: hello/templates/goodbye\ngoodbye: world")
247 is.Contains(res.Manifest, "hello: Earth")
248 is.NotContains(res.Manifest, "hello: {{ template \"_planet\" . }}")
249 is.NotContains(res.Manifest, "empty")
250
251 _, err = instAction.cfg.Releases.Get(res.Name, res.Version)
252 is.Error(err)
253 is.Len(res.Hooks, 1)
254 is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "expect hook to not be marked as run")
255 is.Equal(res.Info.Description, "Dry run complete")
256 }
257
258 func TestInstallRelease_DryRunHiddenSecret(t *testing.T) {
259 is := assert.New(t)
260 instAction := installAction(t)
261
262
263 instAction.DryRun = true
264 vals := map[string]interface{}{}
265 res, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals)
266 if err != nil {
267 t.Fatalf("Failed install: %s", err)
268 }
269 is.Contains(res.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret")
270
271 _, err = instAction.cfg.Releases.Get(res.Name, res.Version)
272 is.Error(err)
273 is.Equal(res.Info.Description, "Dry run complete")
274
275
276 instAction.HideSecret = true
277 vals = map[string]interface{}{}
278 res2, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals)
279 if err != nil {
280 t.Fatalf("Failed install: %s", err)
281 }
282
283 is.NotContains(res2.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret")
284
285 _, err = instAction.cfg.Releases.Get(res2.Name, res2.Version)
286 is.Error(err)
287 is.Equal(res2.Info.Description, "Dry run complete")
288
289
290 instAction.DryRun = false
291 vals = map[string]interface{}{}
292 _, err = instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals)
293 if err == nil {
294 t.Fatalf("Did not get expected an error when dry-run false and hide secret is true")
295 }
296 }
297
298
299 func TestInstallRelease_DryRun_Lookup(t *testing.T) {
300 is := assert.New(t)
301 instAction := installAction(t)
302 instAction.DryRun = true
303 vals := map[string]interface{}{}
304
305 mockChart := buildChart(withSampleTemplates())
306 mockChart.Templates = append(mockChart.Templates, &chart.File{
307 Name: "templates/lookup",
308 Data: []byte(`goodbye: {{ lookup "v1" "Namespace" "" "___" }}`),
309 })
310
311 res, err := instAction.Run(mockChart, vals)
312 if err != nil {
313 t.Fatalf("Failed install: %s", err)
314 }
315
316 is.Contains(res.Manifest, "goodbye: map[]")
317 }
318
319 func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) {
320 is := assert.New(t)
321 instAction := installAction(t)
322 instAction.DryRun = true
323 vals := map[string]interface{}{}
324 _, err := instAction.Run(buildChart(withSampleIncludingIncorrectTemplates()), vals)
325 expectedErr := "\"hello/templates/incorrect\" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh"
326 if err == nil {
327 t.Fatalf("Install should fail containing error: %s", expectedErr)
328 }
329 if err != nil {
330 is.Contains(err.Error(), expectedErr)
331 }
332 }
333
334 func TestInstallRelease_NoHooks(t *testing.T) {
335 is := assert.New(t)
336 instAction := installAction(t)
337 instAction.DisableHooks = true
338 instAction.ReleaseName = "no-hooks"
339 instAction.cfg.Releases.Create(releaseStub())
340
341 vals := map[string]interface{}{}
342 res, err := instAction.Run(buildChart(), vals)
343 if err != nil {
344 t.Fatalf("Failed install: %s", err)
345 }
346
347 is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "hooks should not run with no-hooks")
348 }
349
350 func TestInstallRelease_FailedHooks(t *testing.T) {
351 is := assert.New(t)
352 instAction := installAction(t)
353 instAction.ReleaseName = "failed-hooks"
354 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
355 failer.WatchUntilReadyError = fmt.Errorf("Failed watch")
356 instAction.cfg.KubeClient = failer
357
358 vals := map[string]interface{}{}
359 res, err := instAction.Run(buildChart(), vals)
360 is.Error(err)
361 is.Contains(res.Info.Description, "failed post-install")
362 is.Equal(release.StatusFailed, res.Info.Status)
363 }
364
365 func TestInstallRelease_ReplaceRelease(t *testing.T) {
366 is := assert.New(t)
367 instAction := installAction(t)
368 instAction.Replace = true
369
370 rel := releaseStub()
371 rel.Info.Status = release.StatusUninstalled
372 instAction.cfg.Releases.Create(rel)
373 instAction.ReleaseName = rel.Name
374
375 vals := map[string]interface{}{}
376 res, err := instAction.Run(buildChart(), vals)
377 is.NoError(err)
378
379
380 is.Equal(2, res.Version)
381 is.Equal(res.Name, rel.Name)
382
383 getres, err := instAction.cfg.Releases.Get(rel.Name, res.Version)
384 is.NoError(err)
385 is.Equal(getres.Info.Status, release.StatusDeployed)
386 }
387
388 func TestInstallRelease_KubeVersion(t *testing.T) {
389 is := assert.New(t)
390 instAction := installAction(t)
391 vals := map[string]interface{}{}
392 _, err := instAction.Run(buildChart(withKube(">=0.0.0")), vals)
393 is.NoError(err)
394
395
396 instAction.ReleaseName = "should-fail"
397 vals = map[string]interface{}{}
398 _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals)
399 is.Error(err)
400 is.Contains(err.Error(), "chart requires kubeVersion")
401 }
402
403 func TestInstallRelease_Wait(t *testing.T) {
404 is := assert.New(t)
405 instAction := installAction(t)
406 instAction.ReleaseName = "come-fail-away"
407 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
408 failer.WaitError = fmt.Errorf("I timed out")
409 instAction.cfg.KubeClient = failer
410 instAction.Wait = true
411 vals := map[string]interface{}{}
412
413 goroutines := runtime.NumGoroutine()
414
415 res, err := instAction.Run(buildChart(), vals)
416 is.Error(err)
417 is.Contains(res.Info.Description, "I timed out")
418 is.Equal(res.Info.Status, release.StatusFailed)
419
420 is.Equal(goroutines, runtime.NumGoroutine())
421 }
422 func TestInstallRelease_Wait_Interrupted(t *testing.T) {
423 is := assert.New(t)
424 instAction := installAction(t)
425 instAction.ReleaseName = "interrupted-release"
426 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
427 failer.WaitDuration = 10 * time.Second
428 instAction.cfg.KubeClient = failer
429 instAction.Wait = true
430 vals := map[string]interface{}{}
431
432 ctx := context.Background()
433 ctx, cancel := context.WithCancel(ctx)
434 time.AfterFunc(time.Second, cancel)
435
436 goroutines := runtime.NumGoroutine()
437
438 res, err := instAction.RunWithContext(ctx, buildChart(), vals)
439 is.Error(err)
440 is.Contains(res.Info.Description, "Release \"interrupted-release\" failed: context canceled")
441 is.Equal(res.Info.Status, release.StatusFailed)
442
443 is.Equal(goroutines+1, runtime.NumGoroutine())
444 time.Sleep(10 * time.Second)
445 is.Equal(goroutines, runtime.NumGoroutine())
446 }
447 func TestInstallRelease_WaitForJobs(t *testing.T) {
448 is := assert.New(t)
449 instAction := installAction(t)
450 instAction.ReleaseName = "come-fail-away"
451 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
452 failer.WaitError = fmt.Errorf("I timed out")
453 instAction.cfg.KubeClient = failer
454 instAction.Wait = true
455 instAction.WaitForJobs = true
456 vals := map[string]interface{}{}
457
458 res, err := instAction.Run(buildChart(), vals)
459 is.Error(err)
460 is.Contains(res.Info.Description, "I timed out")
461 is.Equal(res.Info.Status, release.StatusFailed)
462 }
463
464 func TestInstallRelease_Atomic(t *testing.T) {
465 is := assert.New(t)
466
467 t.Run("atomic uninstall succeeds", func(t *testing.T) {
468 instAction := installAction(t)
469 instAction.ReleaseName = "come-fail-away"
470 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
471 failer.WaitError = fmt.Errorf("I timed out")
472 instAction.cfg.KubeClient = failer
473 instAction.Atomic = true
474
475
476 instAction.DisableHooks = true
477 vals := map[string]interface{}{}
478
479 res, err := instAction.Run(buildChart(), vals)
480 is.Error(err)
481 is.Contains(err.Error(), "I timed out")
482 is.Contains(err.Error(), "atomic")
483
484
485 _, err = instAction.cfg.Releases.Get(res.Name, res.Version)
486 is.Error(err)
487 is.Equal(err, driver.ErrReleaseNotFound)
488 })
489
490 t.Run("atomic uninstall fails", func(t *testing.T) {
491 instAction := installAction(t)
492 instAction.ReleaseName = "come-fail-away-with-me"
493 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
494 failer.WaitError = fmt.Errorf("I timed out")
495 failer.DeleteError = fmt.Errorf("uninstall fail")
496 instAction.cfg.KubeClient = failer
497 instAction.Atomic = true
498 vals := map[string]interface{}{}
499
500 _, err := instAction.Run(buildChart(), vals)
501 is.Error(err)
502 is.Contains(err.Error(), "I timed out")
503 is.Contains(err.Error(), "uninstall fail")
504 is.Contains(err.Error(), "an error occurred while uninstalling the release")
505 })
506 }
507 func TestInstallRelease_Atomic_Interrupted(t *testing.T) {
508
509 is := assert.New(t)
510 instAction := installAction(t)
511 instAction.ReleaseName = "interrupted-release"
512 failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
513 failer.WaitDuration = 10 * time.Second
514 instAction.cfg.KubeClient = failer
515 instAction.Atomic = true
516 vals := map[string]interface{}{}
517
518 ctx := context.Background()
519 ctx, cancel := context.WithCancel(ctx)
520 time.AfterFunc(time.Second, cancel)
521
522 res, err := instAction.RunWithContext(ctx, buildChart(), vals)
523 is.Error(err)
524 is.Contains(err.Error(), "context canceled")
525 is.Contains(err.Error(), "atomic")
526 is.Contains(err.Error(), "uninstalled")
527
528
529 _, err = instAction.cfg.Releases.Get(res.Name, res.Version)
530 is.Error(err)
531 is.Equal(err, driver.ErrReleaseNotFound)
532
533 }
534 func TestNameTemplate(t *testing.T) {
535 testCases := []nameTemplateTestCase{
536
537 {
538 tpl: "foobar",
539 expected: "foobar",
540 expectedErrorStr: "",
541 },
542
543 {
544 tpl: "foobar-{{randNumeric 6}}",
545 expected: "foobar-[0-9]{6}$",
546 expectedErrorStr: "",
547 },
548
549 {
550 tpl: "foobar-{{randNumeric 4}}-baz",
551 expected: "foobar-[0-9]{4}-baz$",
552 expectedErrorStr: "",
553 },
554
555 {
556 tpl: "foobar-{{randInteger}}",
557 expected: "",
558 expectedErrorStr: "function \"randInteger\" not defined",
559 },
560
561 {
562 tpl: "foobar-{{",
563 expected: "",
564 expectedErrorStr: "template: name-template:1: unclosed action",
565 },
566 }
567
568 for _, tc := range testCases {
569
570 n, err := TemplateName(tc.tpl)
571 if err != nil {
572 if tc.expectedErrorStr == "" {
573 t.Errorf("Was not expecting error, but got: %v", err)
574 continue
575 }
576 re, compErr := regexp.Compile(tc.expectedErrorStr)
577 if compErr != nil {
578 t.Errorf("Expected error string failed to compile: %v", compErr)
579 continue
580 }
581 if !re.MatchString(err.Error()) {
582 t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err)
583 continue
584 }
585 }
586 if err == nil && tc.expectedErrorStr != "" {
587 t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr)
588 }
589
590 if tc.expected != "" {
591 re, err := regexp.Compile(tc.expected)
592 if err != nil {
593 t.Errorf("Expected string failed to compile: %v", err)
594 continue
595 }
596 if !re.MatchString(n) {
597 t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n)
598 }
599 }
600 }
601 }
602
603 func TestInstallReleaseOutputDir(t *testing.T) {
604 is := assert.New(t)
605 instAction := installAction(t)
606 vals := map[string]interface{}{}
607
608 dir := t.TempDir()
609
610 instAction.OutputDir = dir
611
612 _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals)
613 if err != nil {
614 t.Fatalf("Failed install: %s", err)
615 }
616
617 _, err = os.Stat(filepath.Join(dir, "hello/templates/goodbye"))
618 is.NoError(err)
619
620 _, err = os.Stat(filepath.Join(dir, "hello/templates/hello"))
621 is.NoError(err)
622
623 _, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials"))
624 is.NoError(err)
625
626 _, err = os.Stat(filepath.Join(dir, "hello/templates/rbac"))
627 is.NoError(err)
628
629 test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt")
630
631 _, err = os.Stat(filepath.Join(dir, "hello/templates/empty"))
632 is.True(os.IsNotExist(err))
633 }
634
635 func TestInstallOutputDirWithReleaseName(t *testing.T) {
636 is := assert.New(t)
637 instAction := installAction(t)
638 vals := map[string]interface{}{}
639
640 dir := t.TempDir()
641
642 instAction.OutputDir = dir
643 instAction.UseReleaseName = true
644 instAction.ReleaseName = "madra"
645
646 newDir := filepath.Join(dir, instAction.ReleaseName)
647
648 _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals)
649 if err != nil {
650 t.Fatalf("Failed install: %s", err)
651 }
652
653 _, err = os.Stat(filepath.Join(newDir, "hello/templates/goodbye"))
654 is.NoError(err)
655
656 _, err = os.Stat(filepath.Join(newDir, "hello/templates/hello"))
657 is.NoError(err)
658
659 _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials"))
660 is.NoError(err)
661
662 _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac"))
663 is.NoError(err)
664
665 test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt")
666
667 _, err = os.Stat(filepath.Join(newDir, "hello/templates/empty"))
668 is.True(os.IsNotExist(err))
669 }
670
671 func TestNameAndChart(t *testing.T) {
672 is := assert.New(t)
673 instAction := installAction(t)
674 chartName := "./foo"
675
676 name, chrt, err := instAction.NameAndChart([]string{chartName})
677 if err != nil {
678 t.Fatal(err)
679 }
680 is.Equal(instAction.ReleaseName, name)
681 is.Equal(chartName, chrt)
682
683 instAction.GenerateName = true
684 _, _, err = instAction.NameAndChart([]string{"foo", chartName})
685 if err == nil {
686 t.Fatal("expected an error")
687 }
688 is.Equal("cannot set --generate-name and also specify a name", err.Error())
689
690 instAction.GenerateName = false
691 instAction.NameTemplate = "{{ . }}"
692 _, _, err = instAction.NameAndChart([]string{"foo", chartName})
693 if err == nil {
694 t.Fatal("expected an error")
695 }
696 is.Equal("cannot set --name-template and also specify a name", err.Error())
697
698 instAction.NameTemplate = ""
699 instAction.ReleaseName = ""
700 _, _, err = instAction.NameAndChart([]string{chartName})
701 if err == nil {
702 t.Fatal("expected an error")
703 }
704 is.Equal("must either provide a name or specify --generate-name", err.Error())
705
706 instAction.NameTemplate = ""
707 instAction.ReleaseName = ""
708 _, _, err = instAction.NameAndChart([]string{"foo", chartName, "bar"})
709 if err == nil {
710 t.Fatal("expected an error")
711 }
712 is.Equal("expected at most two arguments, unexpected arguments: bar", err.Error())
713 }
714
715 func TestNameAndChartGenerateName(t *testing.T) {
716 is := assert.New(t)
717 instAction := installAction(t)
718
719 instAction.ReleaseName = ""
720 instAction.GenerateName = true
721
722 tests := []struct {
723 Name string
724 Chart string
725 ExpectedName string
726 }{
727 {
728 "local filepath",
729 "./chart",
730 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
731 },
732 {
733 "dot filepath",
734 ".",
735 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
736 },
737 {
738 "empty filepath",
739 "",
740 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
741 },
742 {
743 "packaged chart",
744 "chart.tgz",
745 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
746 },
747 {
748 "packaged chart with .tar.gz extension",
749 "chart.tar.gz",
750 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
751 },
752 {
753 "packaged chart with local extension",
754 "./chart.tgz",
755 fmt.Sprintf("chart-%d", helmtime.Now().Unix()),
756 },
757 }
758
759 for _, tc := range tests {
760 tc := tc
761 t.Run(tc.Name, func(t *testing.T) {
762 t.Parallel()
763
764 name, chrt, err := instAction.NameAndChart([]string{tc.Chart})
765 if err != nil {
766 t.Fatal(err)
767 }
768
769 is.Equal(tc.ExpectedName, name)
770 is.Equal(tc.Chart, chrt)
771 })
772 }
773 }
774
775 func TestInstallWithLabels(t *testing.T) {
776 is := assert.New(t)
777 instAction := installAction(t)
778 instAction.Labels = map[string]string{
779 "key1": "val1",
780 "key2": "val2",
781 }
782 res, err := instAction.Run(buildChart(), nil)
783 if err != nil {
784 t.Fatalf("Failed install: %s", err)
785 }
786
787 is.Equal(instAction.Labels, res.Labels)
788 }
789
790 func TestInstallWithSystemLabels(t *testing.T) {
791 is := assert.New(t)
792 instAction := installAction(t)
793 instAction.Labels = map[string]string{
794 "owner": "val1",
795 "key2": "val2",
796 }
797 _, err := instAction.Run(buildChart(), nil)
798 if err == nil {
799 t.Fatal("expected an error")
800 }
801
802 is.Equal(fmt.Errorf("user suplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err)
803 }
804
View as plain text