github.com/latiif/helm@v2.15.0+incompatible/cmd/helm/install_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 main
    18  
    19  import (
    20  	"io"
    21  	"reflect"
    22  	"regexp"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/spf13/cobra"
    27  	"k8s.io/helm/pkg/helm"
    28  )
    29  
    30  func TestInstall(t *testing.T) {
    31  	tests := []releaseCase{
    32  		// Install, base case
    33  		{
    34  			name:     "basic install",
    35  			args:     []string{"testdata/testcharts/alpine"},
    36  			flags:    strings.Split("--name aeneas", " "),
    37  			expected: "aeneas",
    38  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
    39  		},
    40  		// Install, no hooks
    41  		{
    42  			name:     "install without hooks",
    43  			args:     []string{"testdata/testcharts/alpine"},
    44  			flags:    strings.Split("--name aeneas --no-hooks", " "),
    45  			expected: "aeneas",
    46  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
    47  		},
    48  		// Install, values from cli
    49  		{
    50  			name:     "install with values",
    51  			args:     []string{"testdata/testcharts/alpine"},
    52  			flags:    strings.Split("--name virgil --set foo=bar", " "),
    53  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
    54  			expected: "virgil",
    55  		},
    56  		// Install, values from cli via multiple --set
    57  		{
    58  			name:     "install with multiple values",
    59  			args:     []string{"testdata/testcharts/alpine"},
    60  			flags:    strings.Split("--name virgil --set foo=bar --set bar=foo", " "),
    61  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
    62  			expected: "virgil",
    63  		},
    64  		{
    65  			name:     "install with multiple unordered list values",
    66  			args:     []string{"testdata/testcharts/alpine"},
    67  			flags:    strings.Split("--name virgil --set foo[1].bar=baz,foo[0].baz=bar", " "),
    68  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
    69  			expected: "virgil",
    70  		},
    71  		{
    72  			name:     "install with values",
    73  			args:     []string{"testdata/testcharts/alpine"},
    74  			flags:    strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml", " "),
    75  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
    76  			expected: "virgil",
    77  		},
    78  		// Install, values from multiple yaml
    79  		{
    80  			name:     "install with values",
    81  			args:     []string{"testdata/testcharts/alpine"},
    82  			flags:    strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml -f testdata/testcharts/alpine/more_values.yaml", " "),
    83  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
    84  			expected: "virgil",
    85  		},
    86  		// Install, no charts
    87  		{
    88  			name: "install with no chart specified",
    89  			args: []string{},
    90  			err:  true,
    91  		},
    92  		// Install, re-use name
    93  		{
    94  			name:     "install and replace release",
    95  			args:     []string{"testdata/testcharts/alpine"},
    96  			flags:    strings.Split("--name aeneas --replace", " "),
    97  			expected: "aeneas",
    98  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}),
    99  		},
   100  		// Install, with timeout
   101  		{
   102  			name:     "install with a timeout",
   103  			args:     []string{"testdata/testcharts/alpine"},
   104  			flags:    strings.Split("--name foobar --timeout 120", " "),
   105  			expected: "foobar",
   106  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "foobar"}),
   107  		},
   108  		// Install, with wait
   109  		{
   110  			name:     "install with a wait",
   111  			args:     []string{"testdata/testcharts/alpine"},
   112  			flags:    strings.Split("--name apollo --wait", " "),
   113  			expected: "apollo",
   114  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}),
   115  		},
   116  		// Install, with atomic
   117  		{
   118  			name:     "install with a atomic",
   119  			args:     []string{"testdata/testcharts/alpine"},
   120  			flags:    strings.Split("--name apollo", " "),
   121  			expected: "apollo",
   122  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}),
   123  		},
   124  		// Install, using the name-template
   125  		{
   126  			name:     "install with name-template",
   127  			args:     []string{"testdata/testcharts/alpine"},
   128  			flags:    []string{"--name-template", "{{lower \"FOOBAR\"}}"},
   129  			expected: "foobar",
   130  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "foobar"}),
   131  		},
   132  		{
   133  			name:     "install with custom description",
   134  			args:     []string{"testdata/testcharts/alpine"},
   135  			flags:    []string{"--name", "virgil", "--description", "foobar"},
   136  			expected: "virgil",
   137  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil", Description: "foobar"}),
   138  		},
   139  		// Install, perform chart verification along the way.
   140  		{
   141  			name:  "install with verification, missing provenance",
   142  			args:  []string{"testdata/testcharts/compressedchart-0.1.0.tgz"},
   143  			flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "),
   144  			err:   true,
   145  		},
   146  		{
   147  			name:  "install with verification, directory instead of file",
   148  			args:  []string{"testdata/testcharts/signtest"},
   149  			flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "),
   150  			err:   true,
   151  		},
   152  		{
   153  			name:  "install with verification, valid",
   154  			args:  []string{"testdata/testcharts/signtest-0.1.0.tgz"},
   155  			flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "),
   156  		},
   157  		// Install, chart with missing dependencies in /charts
   158  		{
   159  			name: "install chart with missing dependencies",
   160  			args: []string{"testdata/testcharts/chart-missing-deps"},
   161  			err:  true,
   162  		},
   163  		// Install, chart with bad requirements.yaml in /charts
   164  		{
   165  			name: "install chart with bad requirements.yaml",
   166  			args: []string{"testdata/testcharts/chart-bad-requirements"},
   167  			err:  true,
   168  		},
   169  		// Install, using a bad release name
   170  		{
   171  			name:  "install chart with release name using capitals",
   172  			args:  []string{"testdata/testcharts/alpine"},
   173  			flags: []string{"--name", "FOO"},
   174  			err:   true,
   175  		},
   176  		{
   177  			name:  "install chart with release name using periods",
   178  			args:  []string{"testdata/testcharts/alpine"},
   179  			flags: []string{"--name", "foo.bar"},
   180  		},
   181  		{
   182  			name:  "install chart with release name using underscores",
   183  			args:  []string{"testdata/testcharts/alpine"},
   184  			flags: []string{"--name", "foo_bar"},
   185  			err:   true,
   186  		},
   187  		// Install, using a bad name-template
   188  		{
   189  			name:  "install with name-template",
   190  			args:  []string{"testdata/testcharts/alpine"},
   191  			flags: []string{"--name-template", "{{UPPER \"foobar\"}}"},
   192  			err:   true,
   193  		},
   194  		// Install, using --output json
   195  		{
   196  			name:     "install using output json",
   197  			args:     []string{"testdata/testcharts/alpine"},
   198  			flags:    strings.Split("--name virgil --output json", " "),
   199  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
   200  			expected: regexp.QuoteMeta(`{"name":"virgil","info":{"status":{"code":1},"first_deployed":{"seconds":242085845},"last_deployed":{"seconds":242085845},"Description":"Release mock"},"namespace":"default"}`),
   201  		},
   202  		// Install, using --output yaml
   203  		{
   204  			name:     "install using output yaml",
   205  			args:     []string{"testdata/testcharts/alpine"},
   206  			flags:    strings.Split("--name virgil --output yaml", " "),
   207  			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
   208  			expected: "info:\n  Description: Release mock\n  first_deployed:\n    seconds: 242085845\n  last_deployed:\n    seconds: 242085845\n  status:\n    code: 1\nname: virgil\nnamespace: default\n",
   209  		},
   210  	}
   211  
   212  	runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command {
   213  		return newInstallCmd(c, out)
   214  	})
   215  }
   216  
   217  type nameTemplateTestCase struct {
   218  	tpl              string
   219  	expected         string
   220  	expectedErrorStr string
   221  }
   222  
   223  func TestNameTemplate(t *testing.T) {
   224  	testCases := []nameTemplateTestCase{
   225  		// Just a straight up nop please
   226  		{
   227  			tpl:              "foobar",
   228  			expected:         "foobar",
   229  			expectedErrorStr: "",
   230  		},
   231  		// Random numbers at the end for fun & profit
   232  		{
   233  			tpl:              "foobar-{{randNumeric 6}}",
   234  			expected:         "foobar-[0-9]{6}$",
   235  			expectedErrorStr: "",
   236  		},
   237  		// Random numbers in the middle for fun & profit
   238  		{
   239  			tpl:              "foobar-{{randNumeric 4}}-baz",
   240  			expected:         "foobar-[0-9]{4}-baz$",
   241  			expectedErrorStr: "",
   242  		},
   243  		// No such function
   244  		{
   245  			tpl:              "foobar-{{randInt}}",
   246  			expected:         "",
   247  			expectedErrorStr: "function \"randInt\" not defined",
   248  		},
   249  		// Invalid template
   250  		{
   251  			tpl:              "foobar-{{",
   252  			expected:         "",
   253  			expectedErrorStr: "unexpected unclosed action",
   254  		},
   255  	}
   256  
   257  	for _, tc := range testCases {
   258  
   259  		n, err := generateName(tc.tpl)
   260  		if err != nil {
   261  			if tc.expectedErrorStr == "" {
   262  				t.Errorf("Was not expecting error, but got: %v", err)
   263  				continue
   264  			}
   265  			re, compErr := regexp.Compile(tc.expectedErrorStr)
   266  			if compErr != nil {
   267  				t.Errorf("Expected error string failed to compile: %v", compErr)
   268  				continue
   269  			}
   270  			if !re.MatchString(err.Error()) {
   271  				t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err)
   272  				continue
   273  			}
   274  		}
   275  		if err == nil && tc.expectedErrorStr != "" {
   276  			t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr)
   277  		}
   278  
   279  		if tc.expected != "" {
   280  			re, err := regexp.Compile(tc.expected)
   281  			if err != nil {
   282  				t.Errorf("Expected string failed to compile: %v", err)
   283  				continue
   284  			}
   285  			if !re.MatchString(n) {
   286  				t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n)
   287  			}
   288  		}
   289  	}
   290  }
   291  
   292  func TestMergeValues(t *testing.T) {
   293  	nestedMap := map[string]interface{}{
   294  		"foo": "bar",
   295  		"baz": map[string]string{
   296  			"cool": "stuff",
   297  		},
   298  	}
   299  	anotherNestedMap := map[string]interface{}{
   300  		"foo": "bar",
   301  		"baz": map[string]string{
   302  			"cool":    "things",
   303  			"awesome": "stuff",
   304  		},
   305  	}
   306  	flatMap := map[string]interface{}{
   307  		"foo": "bar",
   308  		"baz": "stuff",
   309  	}
   310  	anotherFlatMap := map[string]interface{}{
   311  		"testing": "fun",
   312  	}
   313  
   314  	testMap := mergeValues(flatMap, nestedMap)
   315  	equal := reflect.DeepEqual(testMap, nestedMap)
   316  	if !equal {
   317  		t.Errorf("Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap)
   318  	}
   319  
   320  	testMap = mergeValues(nestedMap, flatMap)
   321  	equal = reflect.DeepEqual(testMap, flatMap)
   322  	if !equal {
   323  		t.Errorf("Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap)
   324  	}
   325  
   326  	testMap = mergeValues(nestedMap, anotherNestedMap)
   327  	equal = reflect.DeepEqual(testMap, anotherNestedMap)
   328  	if !equal {
   329  		t.Errorf("Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap)
   330  	}
   331  
   332  	testMap = mergeValues(anotherFlatMap, anotherNestedMap)
   333  	expectedMap := map[string]interface{}{
   334  		"testing": "fun",
   335  		"foo":     "bar",
   336  		"baz": map[string]string{
   337  			"cool":    "things",
   338  			"awesome": "stuff",
   339  		},
   340  	}
   341  	equal = reflect.DeepEqual(testMap, expectedMap)
   342  	if !equal {
   343  		t.Errorf("Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap)
   344  	}
   345  }