github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/cmd/helm/helm_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 "bytes" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "regexp" 27 "strings" 28 "testing" 29 30 "github.com/spf13/cobra" 31 32 "k8s.io/client-go/util/homedir" 33 "k8s.io/helm/cmd/helm/installer" 34 "k8s.io/helm/pkg/helm" 35 "k8s.io/helm/pkg/helm/environment" 36 "k8s.io/helm/pkg/helm/helmpath" 37 "k8s.io/helm/pkg/proto/hapi/release" 38 "k8s.io/helm/pkg/repo" 39 ) 40 41 // releaseCmd is a command that works with a FakeClient 42 type releaseCmd func(c *helm.FakeClient, out io.Writer) *cobra.Command 43 44 // runReleaseCases runs a set of release cases through the given releaseCmd. 45 func runReleaseCases(t *testing.T, tests []releaseCase, rcmd releaseCmd) { 46 var buf bytes.Buffer 47 for _, tt := range tests { 48 t.Run(tt.name, func(t *testing.T) { 49 c := &helm.FakeClient{ 50 Rels: tt.rels, 51 Responses: tt.responses, 52 } 53 cmd := rcmd(c, &buf) 54 cmd.ParseFlags(tt.flags) 55 err := cmd.RunE(cmd, tt.args) 56 if (err != nil) != tt.err { 57 t.Errorf("expected error, got '%v'", err) 58 } 59 re := regexp.MustCompile(tt.expected) 60 if !re.Match(buf.Bytes()) { 61 t.Errorf("expected\n%q\ngot\n%q", tt.expected, buf.String()) 62 } 63 buf.Reset() 64 }) 65 } 66 } 67 68 // releaseCase describes a test case that works with releases. 69 type releaseCase struct { 70 name string 71 args []string 72 flags []string 73 // expected is the string to be matched. This supports regular expressions. 74 expected string 75 err bool 76 resp *release.Release 77 // Rels are the available releases at the start of the test. 78 rels []*release.Release 79 responses map[string]release.TestRun_Status 80 } 81 82 // tempHelmHome sets up a Helm Home in a temp dir. 83 // 84 // This does not clean up the directory. You must do that yourself. 85 // You must also set helmHome yourself. 86 func tempHelmHome(t *testing.T) (helmpath.Home, error) { 87 oldhome := settings.Home 88 dir, err := ioutil.TempDir("", "helm_home-") 89 if err != nil { 90 return helmpath.Home("n/"), err 91 } 92 93 settings.Home = helmpath.Home(dir) 94 if err := ensureTestHome(settings.Home, t); err != nil { 95 return helmpath.Home("n/"), err 96 } 97 settings.Home = oldhome 98 return helmpath.Home(dir), nil 99 } 100 101 // ensureTestHome creates a home directory like ensureHome, but without remote references. 102 // 103 // t is used only for logging. 104 func ensureTestHome(home helmpath.Home, t *testing.T) error { 105 configDirectories := []string{home.String(), home.Repository(), home.Cache(), home.LocalRepository(), home.Plugins(), home.Starters()} 106 for _, p := range configDirectories { 107 if fi, err := os.Stat(p); err != nil { 108 if err := os.MkdirAll(p, 0755); err != nil { 109 return fmt.Errorf("Could not create %s: %s", p, err) 110 } 111 } else if !fi.IsDir() { 112 return fmt.Errorf("%s must be a directory", p) 113 } 114 } 115 116 repoFile := home.RepositoryFile() 117 if fi, err := os.Stat(repoFile); err != nil { 118 rf := repo.NewRepoFile() 119 rf.Add(&repo.Entry{ 120 Name: "charts", 121 URL: "http://example.com/foo", 122 Cache: "charts-index.yaml", 123 }, &repo.Entry{ 124 Name: "local", 125 URL: "http://localhost.com:7743/foo", 126 Cache: "local-index.yaml", 127 }) 128 if err := rf.WriteFile(repoFile, 0644); err != nil { 129 return err 130 } 131 } else if fi.IsDir() { 132 return fmt.Errorf("%s must be a file, not a directory", repoFile) 133 } 134 if r, err := repo.LoadRepositoriesFile(repoFile); err == repo.ErrRepoOutOfDate { 135 t.Log("Updating repository file format...") 136 if err := r.WriteFile(repoFile, 0644); err != nil { 137 return err 138 } 139 } 140 141 localRepoIndexFile := home.LocalRepository(installer.LocalRepositoryIndexFile) 142 if fi, err := os.Stat(localRepoIndexFile); err != nil { 143 i := repo.NewIndexFile() 144 if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { 145 return err 146 } 147 148 //TODO: take this out and replace with helm update functionality 149 os.Symlink(localRepoIndexFile, home.CacheIndex("local")) 150 } else if fi.IsDir() { 151 return fmt.Errorf("%s must be a file, not a directory", localRepoIndexFile) 152 } 153 154 t.Logf("$HELM_HOME has been configured at %s.\n", settings.Home.String()) 155 return nil 156 157 } 158 159 func TestRootCmd(t *testing.T) { 160 cleanup := resetEnv() 161 defer cleanup() 162 163 tests := []struct { 164 name string 165 args []string 166 envars map[string]string 167 home string 168 }{ 169 { 170 name: "defaults", 171 args: []string{"home"}, 172 home: filepath.Join(homedir.HomeDir(), ".helm"), 173 }, 174 { 175 name: "with --home set", 176 args: []string{"--home", "/foo"}, 177 home: "/foo", 178 }, 179 { 180 name: "subcommands with --home set", 181 args: []string{"home", "--home", "/foo"}, 182 home: "/foo", 183 }, 184 { 185 name: "with $HELM_HOME set", 186 args: []string{"home"}, 187 envars: map[string]string{"HELM_HOME": "/bar"}, 188 home: "/bar", 189 }, 190 { 191 name: "subcommands with $HELM_HOME set", 192 args: []string{"home"}, 193 envars: map[string]string{"HELM_HOME": "/bar"}, 194 home: "/bar", 195 }, 196 { 197 name: "with $HELM_HOME and --home set", 198 args: []string{"home", "--home", "/foo"}, 199 envars: map[string]string{"HELM_HOME": "/bar"}, 200 home: "/foo", 201 }, 202 } 203 204 // ensure not set locally 205 os.Unsetenv("HELM_HOME") 206 207 for _, tt := range tests { 208 t.Run(tt.name, func(t *testing.T) { 209 defer os.Unsetenv("HELM_HOME") 210 211 for k, v := range tt.envars { 212 os.Setenv(k, v) 213 } 214 215 cmd := newRootCmd(tt.args) 216 cmd.SetOutput(ioutil.Discard) 217 cmd.SetArgs(tt.args) 218 cmd.Run = func(*cobra.Command, []string) {} 219 if err := cmd.Execute(); err != nil { 220 t.Errorf("unexpected error: %s", err) 221 } 222 223 if settings.Home.String() != tt.home { 224 t.Errorf("expected home %q, got %q", tt.home, settings.Home) 225 } 226 homeFlag := cmd.Flag("home").Value.String() 227 homeFlag = os.ExpandEnv(homeFlag) 228 if homeFlag != tt.home { 229 t.Errorf("expected home %q, got %q", tt.home, homeFlag) 230 } 231 }) 232 } 233 } 234 235 func TestTLSFlags(t *testing.T) { 236 cleanup := resetEnv() 237 defer cleanup() 238 239 homePath := os.Getenv("HELM_HOME") 240 if homePath == "" { 241 homePath = filepath.Join(homedir.HomeDir(), ".helm") 242 } 243 244 home := helmpath.Home(homePath) 245 246 tests := []struct { 247 name string 248 args []string 249 envars map[string]string 250 settings environment.EnvSettings 251 }{ 252 { 253 name: "defaults", 254 args: []string{"version", "-c"}, 255 settings: environment.EnvSettings{ 256 TillerHost: "", 257 TillerConnectionTimeout: 300, 258 TillerNamespace: "kube-system", 259 Home: home, 260 Debug: false, 261 KubeContext: "", 262 KubeConfig: "", 263 TLSEnable: false, 264 TLSVerify: false, 265 TLSServerName: "", 266 TLSCaCertFile: home.TLSCaCert(), 267 TLSCertFile: home.TLSCert(), 268 TLSKeyFile: home.TLSKey(), 269 }, 270 }, 271 { 272 name: "tls enable", 273 args: []string{"version", "-c", "--tls"}, 274 settings: environment.EnvSettings{ 275 TillerHost: "", 276 TillerConnectionTimeout: 300, 277 TillerNamespace: "kube-system", 278 Home: home, 279 Debug: false, 280 KubeContext: "", 281 KubeConfig: "", 282 TLSEnable: true, 283 TLSVerify: false, 284 TLSServerName: "", 285 TLSCaCertFile: home.TLSCaCert(), 286 TLSCertFile: home.TLSCert(), 287 TLSKeyFile: home.TLSKey(), 288 }, 289 }, 290 { 291 name: "tls verify", 292 args: []string{"version", "-c", "--tls-verify"}, 293 settings: environment.EnvSettings{ 294 TillerHost: "", 295 TillerConnectionTimeout: 300, 296 TillerNamespace: "kube-system", 297 Home: home, 298 Debug: false, 299 KubeContext: "", 300 KubeConfig: "", 301 TLSEnable: false, 302 TLSVerify: true, 303 TLSServerName: "", 304 TLSCaCertFile: home.TLSCaCert(), 305 TLSCertFile: home.TLSCert(), 306 TLSKeyFile: home.TLSKey(), 307 }, 308 }, 309 { 310 name: "tls servername", 311 args: []string{"version", "-c", "--tls-hostname=foo"}, 312 settings: environment.EnvSettings{ 313 TillerHost: "", 314 TillerConnectionTimeout: 300, 315 TillerNamespace: "kube-system", 316 Home: home, 317 Debug: false, 318 KubeContext: "", 319 KubeConfig: "", 320 TLSEnable: false, 321 TLSVerify: false, 322 TLSServerName: "foo", 323 TLSCaCertFile: home.TLSCaCert(), 324 TLSCertFile: home.TLSCert(), 325 TLSKeyFile: home.TLSKey(), 326 }, 327 }, 328 { 329 name: "tls cacert", 330 args: []string{"version", "-c", "--tls-ca-cert=/foo"}, 331 settings: environment.EnvSettings{ 332 TillerHost: "", 333 TillerConnectionTimeout: 300, 334 TillerNamespace: "kube-system", 335 Home: home, 336 Debug: false, 337 KubeContext: "", 338 KubeConfig: "", 339 TLSEnable: false, 340 TLSVerify: false, 341 TLSServerName: "", 342 TLSCaCertFile: "/foo", 343 TLSCertFile: home.TLSCert(), 344 TLSKeyFile: home.TLSKey(), 345 }, 346 }, 347 { 348 name: "tls cert", 349 args: []string{"version", "-c", "--tls-cert=/foo"}, 350 settings: environment.EnvSettings{ 351 TillerHost: "", 352 TillerConnectionTimeout: 300, 353 TillerNamespace: "kube-system", 354 Home: home, 355 Debug: false, 356 KubeContext: "", 357 KubeConfig: "", 358 TLSEnable: false, 359 TLSVerify: false, 360 TLSServerName: "", 361 TLSCaCertFile: home.TLSCaCert(), 362 TLSCertFile: "/foo", 363 TLSKeyFile: home.TLSKey(), 364 }, 365 }, 366 { 367 name: "tls key", 368 args: []string{"version", "-c", "--tls-key=/foo"}, 369 settings: environment.EnvSettings{ 370 TillerHost: "", 371 TillerConnectionTimeout: 300, 372 TillerNamespace: "kube-system", 373 Home: home, 374 Debug: false, 375 KubeContext: "", 376 KubeConfig: "", 377 TLSEnable: false, 378 TLSVerify: false, 379 TLSServerName: "", 380 TLSCaCertFile: home.TLSCaCert(), 381 TLSCertFile: home.TLSCert(), 382 TLSKeyFile: "/foo", 383 }, 384 }, 385 { 386 name: "tls enable envvar", 387 args: []string{"version", "-c"}, 388 envars: map[string]string{"HELM_TLS_ENABLE": "true"}, 389 settings: environment.EnvSettings{ 390 TillerHost: "", 391 TillerConnectionTimeout: 300, 392 TillerNamespace: "kube-system", 393 Home: home, 394 Debug: false, 395 KubeContext: "", 396 KubeConfig: "", 397 TLSEnable: true, 398 TLSVerify: false, 399 TLSServerName: "", 400 TLSCaCertFile: home.TLSCaCert(), 401 TLSCertFile: home.TLSCert(), 402 TLSKeyFile: home.TLSKey(), 403 }, 404 }, 405 { 406 name: "tls verify envvar", 407 args: []string{"version", "-c"}, 408 envars: map[string]string{"HELM_TLS_VERIFY": "true"}, 409 settings: environment.EnvSettings{ 410 TillerHost: "", 411 TillerConnectionTimeout: 300, 412 TillerNamespace: "kube-system", 413 Home: home, 414 Debug: false, 415 KubeContext: "", 416 KubeConfig: "", 417 TLSEnable: false, 418 TLSVerify: true, 419 TLSServerName: "", 420 TLSCaCertFile: home.TLSCaCert(), 421 TLSCertFile: home.TLSCert(), 422 TLSKeyFile: home.TLSKey(), 423 }, 424 }, 425 { 426 name: "tls servername envvar", 427 args: []string{"version", "-c"}, 428 envars: map[string]string{"HELM_TLS_HOSTNAME": "foo"}, 429 settings: environment.EnvSettings{ 430 TillerHost: "", 431 TillerConnectionTimeout: 300, 432 TillerNamespace: "kube-system", 433 Home: home, 434 Debug: false, 435 KubeContext: "", 436 KubeConfig: "", 437 TLSEnable: false, 438 TLSVerify: false, 439 TLSServerName: "foo", 440 TLSCaCertFile: home.TLSCaCert(), 441 TLSCertFile: home.TLSCert(), 442 TLSKeyFile: home.TLSKey(), 443 }, 444 }, 445 { 446 name: "tls cacert envvar", 447 args: []string{"version", "-c"}, 448 envars: map[string]string{"HELM_TLS_CA_CERT": "/foo"}, 449 settings: environment.EnvSettings{ 450 TillerHost: "", 451 TillerConnectionTimeout: 300, 452 TillerNamespace: "kube-system", 453 Home: home, 454 Debug: false, 455 KubeContext: "", 456 KubeConfig: "", 457 TLSEnable: false, 458 TLSVerify: false, 459 TLSServerName: "", 460 TLSCaCertFile: "/foo", 461 TLSCertFile: home.TLSCert(), 462 TLSKeyFile: home.TLSKey(), 463 }, 464 }, 465 { 466 name: "tls cert envvar", 467 args: []string{"version", "-c"}, 468 envars: map[string]string{"HELM_TLS_CERT": "/foo"}, 469 settings: environment.EnvSettings{ 470 TillerHost: "", 471 TillerConnectionTimeout: 300, 472 TillerNamespace: "kube-system", 473 Home: home, 474 Debug: false, 475 KubeContext: "", 476 KubeConfig: "", 477 TLSEnable: false, 478 TLSVerify: false, 479 TLSServerName: "", 480 TLSCaCertFile: home.TLSCaCert(), 481 TLSCertFile: "/foo", 482 TLSKeyFile: home.TLSKey(), 483 }, 484 }, 485 { 486 name: "tls key envvar", 487 args: []string{"version", "-c"}, 488 envars: map[string]string{"HELM_TLS_KEY": "/foo"}, 489 settings: environment.EnvSettings{ 490 TillerHost: "", 491 TillerConnectionTimeout: 300, 492 TillerNamespace: "kube-system", 493 Home: home, 494 Debug: false, 495 KubeContext: "", 496 KubeConfig: "", 497 TLSEnable: false, 498 TLSVerify: false, 499 TLSServerName: "", 500 TLSCaCertFile: home.TLSCaCert(), 501 TLSCertFile: home.TLSCert(), 502 TLSKeyFile: "/foo", 503 }, 504 }, 505 } 506 507 // ensure not set locally 508 tlsEnvvars := []string{ 509 "HELM_TLS_HOSTNAME", 510 "HELM_TLS_CA_CERT", 511 "HELM_TLS_CERT", 512 "HELM_TLS_KEY", 513 "HELM_TLS_VERIFY", 514 "HELM_TLS_ENABLE", 515 } 516 517 for i := range tlsEnvvars { 518 os.Unsetenv(tlsEnvvars[i]) 519 } 520 521 for _, tt := range tests { 522 t.Run(tt.name, func(t *testing.T) { 523 524 for k, v := range tt.envars { 525 os.Setenv(k, v) 526 defer os.Unsetenv(k) 527 } 528 529 cmd := newRootCmd(tt.args) 530 cmd.SetOutput(ioutil.Discard) 531 cmd.SetArgs(tt.args) 532 cmd.Run = func(*cobra.Command, []string) {} 533 if err := cmd.Execute(); err != nil { 534 t.Errorf("unexpected error: %s", err) 535 } 536 537 if settings != tt.settings { 538 t.Errorf("expected settings %v, got %v", tt.settings, settings) 539 } 540 }) 541 } 542 } 543 544 func resetEnv() func() { 545 origSettings := settings 546 origEnv := os.Environ() 547 return func() { 548 settings = origSettings 549 for _, pair := range origEnv { 550 kv := strings.SplitN(pair, "=", 2) 551 os.Setenv(kv[0], kv[1]) 552 } 553 } 554 }