github.com/sdbaiguanghe/helm@v2.16.7+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 }