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  }