github.com/flant/helm@v2.8.1+incompatible/cmd/helm/installer/install_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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 installer // import "k8s.io/helm/cmd/helm/installer" 18 19 import ( 20 "os" 21 "path/filepath" 22 "reflect" 23 "testing" 24 25 "github.com/ghodss/yaml" 26 "k8s.io/api/core/v1" 27 "k8s.io/api/extensions/v1beta1" 28 apierrors "k8s.io/apimachinery/pkg/api/errors" 29 "k8s.io/apimachinery/pkg/runtime" 30 "k8s.io/client-go/kubernetes/fake" 31 testcore "k8s.io/client-go/testing" 32 33 "k8s.io/helm/pkg/chartutil" 34 "k8s.io/helm/pkg/version" 35 ) 36 37 func TestDeploymentManifest(t *testing.T) { 38 tests := []struct { 39 name string 40 image string 41 canary bool 42 expect string 43 imagePullPolicy v1.PullPolicy 44 }{ 45 {"default", "", false, "gcr.io/kubernetes-helm/tiller:" + version.Version, "IfNotPresent"}, 46 {"canary", "example.com/tiller", true, "gcr.io/kubernetes-helm/tiller:canary", "Always"}, 47 {"custom", "example.com/tiller:latest", false, "example.com/tiller:latest", "IfNotPresent"}, 48 } 49 50 for _, tt := range tests { 51 o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary}) 52 if err != nil { 53 t.Fatalf("%s: error %q", tt.name, err) 54 } 55 var dep v1beta1.Deployment 56 if err := yaml.Unmarshal([]byte(o), &dep); err != nil { 57 t.Fatalf("%s: error %q", tt.name, err) 58 } 59 60 if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect { 61 t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got) 62 } 63 64 if got := dep.Spec.Template.Spec.Containers[0].ImagePullPolicy; got != tt.imagePullPolicy { 65 t.Errorf("%s: expected imagePullPolicy %q, got %q", tt.name, tt.imagePullPolicy, got) 66 } 67 68 if got := dep.Spec.Template.Spec.Containers[0].Env[0].Value; got != v1.NamespaceDefault { 69 t.Errorf("%s: expected namespace %q, got %q", tt.name, v1.NamespaceDefault, got) 70 } 71 } 72 } 73 74 func TestDeploymentManifestForServiceAccount(t *testing.T) { 75 tests := []struct { 76 name string 77 image string 78 canary bool 79 expect string 80 imagePullPolicy v1.PullPolicy 81 serviceAccount string 82 }{ 83 {"withSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", "service-account"}, 84 {"withoutSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", ""}, 85 } 86 for _, tt := range tests { 87 o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount}) 88 if err != nil { 89 t.Fatalf("%s: error %q", tt.name, err) 90 } 91 92 var d v1beta1.Deployment 93 if err := yaml.Unmarshal([]byte(o), &d); err != nil { 94 t.Fatalf("%s: error %q", tt.name, err) 95 } 96 if got := d.Spec.Template.Spec.ServiceAccountName; got != tt.serviceAccount { 97 t.Errorf("%s: expected service account value %q, got %q", tt.name, tt.serviceAccount, got) 98 } 99 } 100 } 101 102 func TestDeploymentManifest_WithTLS(t *testing.T) { 103 tests := []struct { 104 opts Options 105 name string 106 enable string 107 verify string 108 }{ 109 { 110 Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: true}, 111 "tls enable (true), tls verify (true)", 112 "1", 113 "1", 114 }, 115 { 116 Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: false}, 117 "tls enable (true), tls verify (false)", 118 "1", 119 "", 120 }, 121 { 122 Options{Namespace: v1.NamespaceDefault, EnableTLS: false, VerifyTLS: true}, 123 "tls enable (false), tls verify (true)", 124 "1", 125 "1", 126 }, 127 } 128 for _, tt := range tests { 129 o, err := DeploymentManifest(&tt.opts) 130 if err != nil { 131 t.Fatalf("%s: error %q", tt.name, err) 132 } 133 134 var d v1beta1.Deployment 135 if err := yaml.Unmarshal([]byte(o), &d); err != nil { 136 t.Fatalf("%s: error %q", tt.name, err) 137 } 138 // verify environment variable in deployment reflect the use of tls being enabled. 139 if got := d.Spec.Template.Spec.Containers[0].Env[2].Value; got != tt.verify { 140 t.Errorf("%s: expected tls verify env value %q, got %q", tt.name, tt.verify, got) 141 } 142 if got := d.Spec.Template.Spec.Containers[0].Env[3].Value; got != tt.enable { 143 t.Errorf("%s: expected tls enable env value %q, got %q", tt.name, tt.enable, got) 144 } 145 } 146 } 147 148 func TestServiceManifest(t *testing.T) { 149 o, err := ServiceManifest(v1.NamespaceDefault) 150 if err != nil { 151 t.Fatalf("error %q", err) 152 } 153 var svc v1.Service 154 if err := yaml.Unmarshal([]byte(o), &svc); err != nil { 155 t.Fatalf("error %q", err) 156 } 157 158 if got := svc.ObjectMeta.Namespace; got != v1.NamespaceDefault { 159 t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got) 160 } 161 } 162 163 func TestSecretManifest(t *testing.T) { 164 o, err := SecretManifest(&Options{ 165 VerifyTLS: true, 166 EnableTLS: true, 167 Namespace: v1.NamespaceDefault, 168 TLSKeyFile: tlsTestFile(t, "key.pem"), 169 TLSCertFile: tlsTestFile(t, "crt.pem"), 170 TLSCaCertFile: tlsTestFile(t, "ca.pem"), 171 }) 172 173 if err != nil { 174 t.Fatalf("error %q", err) 175 } 176 177 var obj v1.Secret 178 if err := yaml.Unmarshal([]byte(o), &obj); err != nil { 179 t.Fatalf("error %q", err) 180 } 181 182 if got := obj.ObjectMeta.Namespace; got != v1.NamespaceDefault { 183 t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got) 184 } 185 if _, ok := obj.Data["tls.key"]; !ok { 186 t.Errorf("missing 'tls.key' in generated secret object") 187 } 188 if _, ok := obj.Data["tls.crt"]; !ok { 189 t.Errorf("missing 'tls.crt' in generated secret object") 190 } 191 if _, ok := obj.Data["ca.crt"]; !ok { 192 t.Errorf("missing 'ca.crt' in generated secret object") 193 } 194 } 195 196 func TestInstall(t *testing.T) { 197 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 198 199 fc := &fake.Clientset{} 200 fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 201 obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) 202 l := obj.GetLabels() 203 if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { 204 t.Errorf("expected labels = '', got '%s'", l) 205 } 206 i := obj.Spec.Template.Spec.Containers[0].Image 207 if i != image { 208 t.Errorf("expected image = '%s', got '%s'", image, i) 209 } 210 ports := len(obj.Spec.Template.Spec.Containers[0].Ports) 211 if ports != 2 { 212 t.Errorf("expected ports = 2, got '%d'", ports) 213 } 214 return true, obj, nil 215 }) 216 fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) { 217 obj := action.(testcore.CreateAction).GetObject().(*v1.Service) 218 l := obj.GetLabels() 219 if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { 220 t.Errorf("expected labels = '', got '%s'", l) 221 } 222 n := obj.ObjectMeta.Namespace 223 if n != v1.NamespaceDefault { 224 t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n) 225 } 226 return true, obj, nil 227 }) 228 229 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image} 230 if err := Install(fc, opts); err != nil { 231 t.Errorf("unexpected error: %#+v", err) 232 } 233 234 if actions := fc.Actions(); len(actions) != 2 { 235 t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions)) 236 } 237 } 238 239 func TestInstall_WithTLS(t *testing.T) { 240 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 241 name := "tiller-secret" 242 243 fc := &fake.Clientset{} 244 fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 245 obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) 246 l := obj.GetLabels() 247 if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { 248 t.Errorf("expected labels = '', got '%s'", l) 249 } 250 i := obj.Spec.Template.Spec.Containers[0].Image 251 if i != image { 252 t.Errorf("expected image = '%s', got '%s'", image, i) 253 } 254 return true, obj, nil 255 }) 256 fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) { 257 obj := action.(testcore.CreateAction).GetObject().(*v1.Service) 258 l := obj.GetLabels() 259 if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { 260 t.Errorf("expected labels = '', got '%s'", l) 261 } 262 n := obj.ObjectMeta.Namespace 263 if n != v1.NamespaceDefault { 264 t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n) 265 } 266 return true, obj, nil 267 }) 268 fc.AddReactor("create", "secrets", func(action testcore.Action) (bool, runtime.Object, error) { 269 obj := action.(testcore.CreateAction).GetObject().(*v1.Secret) 270 if l := obj.GetLabels(); reflect.DeepEqual(l, map[string]string{"app": "helm"}) { 271 t.Errorf("expected labels = '', got '%s'", l) 272 } 273 if n := obj.ObjectMeta.Namespace; n != v1.NamespaceDefault { 274 t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n) 275 } 276 if s := obj.ObjectMeta.Name; s != name { 277 t.Errorf("expected name = '%s', got '%s'", name, s) 278 } 279 if _, ok := obj.Data["tls.key"]; !ok { 280 t.Errorf("missing 'tls.key' in generated secret object") 281 } 282 if _, ok := obj.Data["tls.crt"]; !ok { 283 t.Errorf("missing 'tls.crt' in generated secret object") 284 } 285 if _, ok := obj.Data["ca.crt"]; !ok { 286 t.Errorf("missing 'ca.crt' in generated secret object") 287 } 288 return true, obj, nil 289 }) 290 291 opts := &Options{ 292 Namespace: v1.NamespaceDefault, 293 ImageSpec: image, 294 EnableTLS: true, 295 VerifyTLS: true, 296 TLSKeyFile: tlsTestFile(t, "key.pem"), 297 TLSCertFile: tlsTestFile(t, "crt.pem"), 298 TLSCaCertFile: tlsTestFile(t, "ca.pem"), 299 } 300 301 if err := Install(fc, opts); err != nil { 302 t.Errorf("unexpected error: %#+v", err) 303 } 304 305 if actions := fc.Actions(); len(actions) != 3 { 306 t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) 307 } 308 } 309 310 func TestInstall_canary(t *testing.T) { 311 fc := &fake.Clientset{} 312 fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 313 obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) 314 i := obj.Spec.Template.Spec.Containers[0].Image 315 if i != "gcr.io/kubernetes-helm/tiller:canary" { 316 t.Errorf("expected canary image, got '%s'", i) 317 } 318 return true, obj, nil 319 }) 320 fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) { 321 obj := action.(testcore.CreateAction).GetObject().(*v1.Service) 322 return true, obj, nil 323 }) 324 325 opts := &Options{Namespace: v1.NamespaceDefault, UseCanary: true} 326 if err := Install(fc, opts); err != nil { 327 t.Errorf("unexpected error: %#+v", err) 328 } 329 330 if actions := fc.Actions(); len(actions) != 2 { 331 t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions)) 332 } 333 } 334 335 func TestUpgrade(t *testing.T) { 336 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 337 serviceAccount := "newServiceAccount" 338 existingDeployment, _ := deployment(&Options{ 339 Namespace: v1.NamespaceDefault, 340 ImageSpec: "imageToReplace:v1.0.0", 341 ServiceAccount: "serviceAccountToReplace", 342 UseCanary: false, 343 }) 344 existingService := service(v1.NamespaceDefault) 345 346 fc := &fake.Clientset{} 347 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 348 return true, existingDeployment, nil 349 }) 350 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 351 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 352 i := obj.Spec.Template.Spec.Containers[0].Image 353 if i != image { 354 t.Errorf("expected image = '%s', got '%s'", image, i) 355 } 356 sa := obj.Spec.Template.Spec.ServiceAccountName 357 if sa != serviceAccount { 358 t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) 359 } 360 return true, obj, nil 361 }) 362 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 363 return true, existingService, nil 364 }) 365 366 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount} 367 if err := Upgrade(fc, opts); err != nil { 368 t.Errorf("unexpected error: %#+v", err) 369 } 370 371 if actions := fc.Actions(); len(actions) != 3 { 372 t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) 373 } 374 } 375 376 func TestUpgrade_serviceNotFound(t *testing.T) { 377 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 378 379 existingDeployment, _ := deployment(&Options{ 380 Namespace: v1.NamespaceDefault, 381 ImageSpec: "imageToReplace", 382 UseCanary: false, 383 }) 384 385 fc := &fake.Clientset{} 386 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 387 return true, existingDeployment, nil 388 }) 389 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 390 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 391 i := obj.Spec.Template.Spec.Containers[0].Image 392 if i != image { 393 t.Errorf("expected image = '%s', got '%s'", image, i) 394 } 395 return true, obj, nil 396 }) 397 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 398 return true, nil, apierrors.NewNotFound(v1.Resource("services"), "1") 399 }) 400 fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) { 401 obj := action.(testcore.CreateAction).GetObject().(*v1.Service) 402 n := obj.ObjectMeta.Namespace 403 if n != v1.NamespaceDefault { 404 t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n) 405 } 406 return true, obj, nil 407 }) 408 409 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image} 410 if err := Upgrade(fc, opts); err != nil { 411 t.Errorf("unexpected error: %#+v", err) 412 } 413 414 if actions := fc.Actions(); len(actions) != 4 { 415 t.Errorf("unexpected actions: %v, expected 4 actions got %d", actions, len(actions)) 416 } 417 } 418 419 func TestUgrade_newerVersion(t *testing.T) { 420 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 421 serviceAccount := "newServiceAccount" 422 existingDeployment, _ := deployment(&Options{ 423 Namespace: v1.NamespaceDefault, 424 ImageSpec: "imageToReplace:v100.5.0", 425 ServiceAccount: "serviceAccountToReplace", 426 UseCanary: false, 427 }) 428 existingService := service(v1.NamespaceDefault) 429 430 fc := &fake.Clientset{} 431 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 432 return true, existingDeployment, nil 433 }) 434 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 435 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 436 i := obj.Spec.Template.Spec.Containers[0].Image 437 if i != image { 438 t.Errorf("expected image = '%s', got '%s'", image, i) 439 } 440 sa := obj.Spec.Template.Spec.ServiceAccountName 441 if sa != serviceAccount { 442 t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) 443 } 444 return true, obj, nil 445 }) 446 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 447 return true, existingService, nil 448 }) 449 450 opts := &Options{ 451 Namespace: v1.NamespaceDefault, 452 ImageSpec: image, 453 ServiceAccount: serviceAccount, 454 ForceUpgrade: false, 455 } 456 if err := Upgrade(fc, opts); err == nil { 457 t.Errorf("Expected error because the deployed version is newer") 458 } 459 460 if actions := fc.Actions(); len(actions) != 1 { 461 t.Errorf("unexpected actions: %v, expected 1 action got %d", actions, len(actions)) 462 } 463 464 opts = &Options{ 465 Namespace: v1.NamespaceDefault, 466 ImageSpec: image, 467 ServiceAccount: serviceAccount, 468 ForceUpgrade: true, 469 } 470 if err := Upgrade(fc, opts); err != nil { 471 t.Errorf("unexpected error: %#+v", err) 472 } 473 474 if actions := fc.Actions(); len(actions) != 4 { 475 t.Errorf("unexpected actions: %v, expected 4 action got %d", actions, len(actions)) 476 } 477 } 478 479 func TestUpgrade_identical(t *testing.T) { 480 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 481 serviceAccount := "newServiceAccount" 482 existingDeployment, _ := deployment(&Options{ 483 Namespace: v1.NamespaceDefault, 484 ImageSpec: "imageToReplace:v2.0.0", 485 ServiceAccount: "serviceAccountToReplace", 486 UseCanary: false, 487 }) 488 existingService := service(v1.NamespaceDefault) 489 490 fc := &fake.Clientset{} 491 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 492 return true, existingDeployment, nil 493 }) 494 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 495 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 496 i := obj.Spec.Template.Spec.Containers[0].Image 497 if i != image { 498 t.Errorf("expected image = '%s', got '%s'", image, i) 499 } 500 sa := obj.Spec.Template.Spec.ServiceAccountName 501 if sa != serviceAccount { 502 t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) 503 } 504 return true, obj, nil 505 }) 506 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 507 return true, existingService, nil 508 }) 509 510 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount} 511 if err := Upgrade(fc, opts); err != nil { 512 t.Errorf("unexpected error: %#+v", err) 513 } 514 515 if actions := fc.Actions(); len(actions) != 3 { 516 t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) 517 } 518 } 519 520 func TestUpgrade_canaryClient(t *testing.T) { 521 image := "gcr.io/kubernetes-helm/tiller:canary" 522 serviceAccount := "newServiceAccount" 523 existingDeployment, _ := deployment(&Options{ 524 Namespace: v1.NamespaceDefault, 525 ImageSpec: "imageToReplace:v1.0.0", 526 ServiceAccount: "serviceAccountToReplace", 527 UseCanary: false, 528 }) 529 existingService := service(v1.NamespaceDefault) 530 531 fc := &fake.Clientset{} 532 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 533 return true, existingDeployment, nil 534 }) 535 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 536 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 537 i := obj.Spec.Template.Spec.Containers[0].Image 538 if i != image { 539 t.Errorf("expected image = '%s', got '%s'", image, i) 540 } 541 sa := obj.Spec.Template.Spec.ServiceAccountName 542 if sa != serviceAccount { 543 t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) 544 } 545 return true, obj, nil 546 }) 547 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 548 return true, existingService, nil 549 }) 550 551 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount} 552 if err := Upgrade(fc, opts); err != nil { 553 t.Errorf("unexpected error: %#+v", err) 554 } 555 556 if actions := fc.Actions(); len(actions) != 3 { 557 t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) 558 } 559 } 560 561 func TestUpgrade_canaryServer(t *testing.T) { 562 image := "gcr.io/kubernetes-helm/tiller:v2.0.0" 563 serviceAccount := "newServiceAccount" 564 existingDeployment, _ := deployment(&Options{ 565 Namespace: v1.NamespaceDefault, 566 ImageSpec: "imageToReplace:canary", 567 ServiceAccount: "serviceAccountToReplace", 568 UseCanary: false, 569 }) 570 existingService := service(v1.NamespaceDefault) 571 572 fc := &fake.Clientset{} 573 fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 574 return true, existingDeployment, nil 575 }) 576 fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { 577 obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) 578 i := obj.Spec.Template.Spec.Containers[0].Image 579 if i != image { 580 t.Errorf("expected image = '%s', got '%s'", image, i) 581 } 582 sa := obj.Spec.Template.Spec.ServiceAccountName 583 if sa != serviceAccount { 584 t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa) 585 } 586 return true, obj, nil 587 }) 588 fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { 589 return true, existingService, nil 590 }) 591 592 opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount} 593 if err := Upgrade(fc, opts); err != nil { 594 t.Errorf("unexpected error: %#+v", err) 595 } 596 597 if actions := fc.Actions(); len(actions) != 3 { 598 t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) 599 } 600 } 601 602 func tlsTestFile(t *testing.T, path string) string { 603 const tlsTestDir = "../../../testdata" 604 path = filepath.Join(tlsTestDir, path) 605 if _, err := os.Stat(path); os.IsNotExist(err) { 606 t.Fatalf("tls test file %s does not exist", path) 607 } 608 return path 609 } 610 func TestDeploymentManifest_WithNodeSelectors(t *testing.T) { 611 tests := []struct { 612 opts Options 613 name string 614 expect map[string]interface{} 615 }{ 616 { 617 Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller"}, 618 "nodeSelector app=tiller", 619 map[string]interface{}{"app": "tiller"}, 620 }, 621 { 622 Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,helm=rocks"}, 623 "nodeSelector app=tiller, helm=rocks", 624 map[string]interface{}{"app": "tiller", "helm": "rocks"}, 625 }, 626 // note: nodeSelector key and value are strings 627 { 628 Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,minCoolness=1"}, 629 "nodeSelector app=tiller, helm=rocks", 630 map[string]interface{}{"app": "tiller", "minCoolness": "1"}, 631 }, 632 } 633 for _, tt := range tests { 634 o, err := DeploymentManifest(&tt.opts) 635 if err != nil { 636 t.Fatalf("%s: error %q", tt.name, err) 637 } 638 639 var d v1beta1.Deployment 640 if err := yaml.Unmarshal([]byte(o), &d); err != nil { 641 t.Fatalf("%s: error %q", tt.name, err) 642 } 643 // Verify that environment variables in Deployment reflect the use of TLS being enabled. 644 got := d.Spec.Template.Spec.NodeSelector 645 for k, v := range tt.expect { 646 if got[k] != v { 647 t.Errorf("%s: expected nodeSelector value %q, got %q", tt.name, tt.expect, got) 648 } 649 } 650 } 651 } 652 func TestDeploymentManifest_WithSetValues(t *testing.T) { 653 tests := []struct { 654 opts Options 655 name string 656 expectPath string 657 expect interface{} 658 }{ 659 { 660 Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.nodeselector.app=tiller"}}, 661 "setValues spec.template.spec.nodeSelector.app=tiller", 662 "spec.template.spec.nodeSelector.app", 663 "tiller", 664 }, 665 { 666 Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.replicas=2"}}, 667 "setValues spec.replicas=2", 668 "spec.replicas", 669 2, 670 }, 671 { 672 Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.activedeadlineseconds=120"}}, 673 "setValues spec.template.spec.activedeadlineseconds=120", 674 "spec.template.spec.activeDeadlineSeconds", 675 120, 676 }, 677 } 678 for _, tt := range tests { 679 o, err := DeploymentManifest(&tt.opts) 680 if err != nil { 681 t.Fatalf("%s: error %q", tt.name, err) 682 } 683 values, err := chartutil.ReadValues([]byte(o)) 684 if err != nil { 685 t.Errorf("Error converting Deployment manifest to Values: %s", err) 686 } 687 // path value 688 pv, err := values.PathValue(tt.expectPath) 689 if err != nil { 690 t.Errorf("Error retrieving path value from Deployment Values: %s", err) 691 } 692 693 // convert our expected value to match the result type for comparison 694 ev := tt.expect 695 switch pvt := pv.(type) { 696 case float64: 697 floatType := reflect.TypeOf(float64(0)) 698 v := reflect.ValueOf(ev) 699 v = reflect.Indirect(v) 700 if !v.Type().ConvertibleTo(floatType) { 701 t.Fatalf("Error converting expected value %v to float64", v.Type()) 702 } 703 fv := v.Convert(floatType) 704 if fv.Float() != pvt { 705 t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv) 706 } 707 default: 708 if pv != tt.expect { 709 t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv) 710 } 711 } 712 } 713 }