github.com/koderover/helm@v2.17.0+incompatible/pkg/tiller/release_update_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 tiller
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  
    27  	"k8s.io/helm/pkg/chartutil"
    28  	"k8s.io/helm/pkg/helm"
    29  	"k8s.io/helm/pkg/proto/hapi/chart"
    30  	"k8s.io/helm/pkg/proto/hapi/release"
    31  	"k8s.io/helm/pkg/proto/hapi/services"
    32  )
    33  
    34  func TestUpdateRelease(t *testing.T) {
    35  	c := helm.NewContext()
    36  	rs := rsFixture()
    37  	rel := releaseStub()
    38  	rs.env.Releases.Create(rel)
    39  
    40  	req := &services.UpdateReleaseRequest{
    41  		Name: rel.Name,
    42  		Chart: &chart.Chart{
    43  			Metadata: &chart.Metadata{Name: "hello"},
    44  			Templates: []*chart.Template{
    45  				{Name: "templates/hello", Data: []byte("hello: world")},
    46  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
    47  			},
    48  		},
    49  	}
    50  	res, err := rs.UpdateRelease(c, req)
    51  	if err != nil {
    52  		t.Fatalf("Failed updated: %s", err)
    53  	}
    54  
    55  	if res.Release.Name == "" {
    56  		t.Errorf("Expected release name.")
    57  	}
    58  
    59  	if res.Release.Name != rel.Name {
    60  		t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name)
    61  	}
    62  
    63  	if res.Release.Namespace != rel.Namespace {
    64  		t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
    65  	}
    66  
    67  	updated := compareStoredAndReturnedRelease(t, *rs, *res)
    68  
    69  	if len(updated.Hooks) != 1 {
    70  		t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
    71  	}
    72  	if updated.Hooks[0].Manifest != manifestWithUpgradeHooks {
    73  		t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest)
    74  	}
    75  
    76  	if updated.Hooks[0].Events[0] != release.Hook_POST_UPGRADE {
    77  		t.Errorf("Expected event 0 to be post upgrade")
    78  	}
    79  
    80  	if updated.Hooks[0].Events[1] != release.Hook_PRE_UPGRADE {
    81  		t.Errorf("Expected event 0 to be pre upgrade")
    82  	}
    83  
    84  	if len(updated.Manifest) == 0 {
    85  		t.Errorf("Expected manifest in %v", res)
    86  	}
    87  
    88  	if res.Release.Config == nil {
    89  		t.Errorf("Got release without config: %#v", res.Release)
    90  	} else if res.Release.Config.Raw != rel.Config.Raw {
    91  		t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw)
    92  	}
    93  
    94  	if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
    95  		t.Errorf("unexpected output: %s", updated.Manifest)
    96  	}
    97  
    98  	if res.Release.Version != 2 {
    99  		t.Errorf("Expected release version to be %v, got %v", 2, res.Release.Version)
   100  	}
   101  
   102  	edesc := "Upgrade complete"
   103  	if got := res.Release.Info.Description; got != edesc {
   104  		t.Errorf("Expected description %q, got %q", edesc, got)
   105  	}
   106  }
   107  func TestUpdateReleasePendingError(t *testing.T) {
   108  	c := helm.NewContext()
   109  	rs := rsFixture()
   110  	rel := releaseStub()
   111  	rs.env.Releases.Create(rel)
   112  	rel2 := releaseStub()
   113  	rel2.Info.Status.Code = release.Status_PENDING_UPGRADE
   114  	rel2.Version = 2
   115  	rs.env.Releases.Create(rel2)
   116  
   117  	req := &services.UpdateReleaseRequest{
   118  		Name: rel.Name,
   119  		Chart: &chart.Chart{
   120  			Metadata: &chart.Metadata{Name: "hello"},
   121  			Templates: []*chart.Template{
   122  				{Name: "templates/hello", Data: []byte("hello: world")},
   123  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   124  			},
   125  		},
   126  	}
   127  	_, err := rs.UpdateRelease(c, req)
   128  	if err == nil {
   129  		t.Fatalf("Expected failure to update")
   130  	}
   131  }
   132  func TestUpdateRelease_ResetValues(t *testing.T) {
   133  	c := helm.NewContext()
   134  	rs := rsFixture()
   135  	rel := releaseStub()
   136  	rs.env.Releases.Create(rel)
   137  
   138  	req := &services.UpdateReleaseRequest{
   139  		Name: rel.Name,
   140  		Chart: &chart.Chart{
   141  			Metadata: &chart.Metadata{Name: "hello"},
   142  			Templates: []*chart.Template{
   143  				{Name: "templates/hello", Data: []byte("hello: world")},
   144  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   145  			},
   146  		},
   147  		ResetValues: true,
   148  	}
   149  	res, err := rs.UpdateRelease(c, req)
   150  	if err != nil {
   151  		t.Fatalf("Failed updated: %s", err)
   152  	}
   153  	// This should have been unset. Config:  &chart.Config{Raw: `name: value`},
   154  	if res.Release.Config != nil && res.Release.Config.Raw != "" {
   155  		t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
   156  	}
   157  }
   158  
   159  func TestUpdateRelease_ReuseValuesWithNoValues(t *testing.T) {
   160  	c := helm.NewContext()
   161  	rs := rsFixture()
   162  
   163  	installReq := &services.InstallReleaseRequest{
   164  		Namespace: "spaced",
   165  		Chart: &chart.Chart{
   166  			Metadata: &chart.Metadata{Name: "hello"},
   167  			Templates: []*chart.Template{
   168  				{Name: "templates/hello", Data: []byte("hello: world")},
   169  				{Name: "templates/hooks", Data: []byte(manifestWithHook)},
   170  			},
   171  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   172  		},
   173  	}
   174  
   175  	installResp, err := rs.InstallRelease(c, installReq)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  
   180  	rel := installResp.Release
   181  	req := &services.UpdateReleaseRequest{
   182  		Name: rel.Name,
   183  		Chart: &chart.Chart{
   184  			Metadata: &chart.Metadata{Name: "hello"},
   185  			Templates: []*chart.Template{
   186  				{Name: "templates/hello", Data: []byte("hello: world")},
   187  			},
   188  		},
   189  		Values:      &chart.Config{Raw: "{}\n"},
   190  		ReuseValues: true,
   191  	}
   192  
   193  	if _, err := rs.UpdateRelease(c, req); err != nil {
   194  		t.Fatalf("Failed updated: %s", err)
   195  	}
   196  }
   197  
   198  func TestUpdateRelease_NestedReuseValues(t *testing.T) {
   199  	c := helm.NewContext()
   200  	rs := rsFixture()
   201  
   202  	installReq := &services.InstallReleaseRequest{
   203  		Namespace: "spaced",
   204  		Chart: &chart.Chart{
   205  			Metadata: &chart.Metadata{Name: "hello"},
   206  			Templates: []*chart.Template{
   207  				{Name: "templates/hello", Data: []byte("hello: world")},
   208  			},
   209  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   210  		},
   211  		Values: &chart.Config{Raw: `
   212  foo: bar
   213  root:
   214    nested: nestedValue
   215    anotherNested: anotherNestedValue
   216  `},
   217  	}
   218  
   219  	installResp, err := rs.InstallRelease(c, installReq)
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  
   224  	rel := installResp.Release
   225  	req := &services.UpdateReleaseRequest{
   226  		Name: rel.Name,
   227  		Chart: &chart.Chart{
   228  			Metadata: &chart.Metadata{Name: "hello"},
   229  			Templates: []*chart.Template{
   230  				{Name: "templates/hello", Data: []byte("hello: world")},
   231  			},
   232  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   233  		},
   234  		Values: &chart.Config{Raw: `
   235  root:
   236    nested: newNestedValue
   237  `},
   238  		ReuseValues: true,
   239  	}
   240  
   241  	res, err := rs.UpdateRelease(c, req)
   242  	if err != nil {
   243  		t.Fatalf("Failed updated: %s", err)
   244  	}
   245  
   246  	expect, _ := chartutil.ReadValues([]byte(`
   247  foo: bar
   248  root:
   249    nested: newNestedValue
   250    anotherNested: anotherNestedValue
   251  `))
   252  
   253  	requestConfig, err := chartutil.ReadValues([]byte(res.Release.Config.Raw))
   254  	if err != nil {
   255  		t.Errorf("Request config could not be parsed: %v", err)
   256  	}
   257  
   258  	if !reflect.DeepEqual(expect, requestConfig) {
   259  		t.Errorf("Expected request config to be %v, got %v", expect, requestConfig)
   260  	}
   261  }
   262  
   263  // This is a regression test for bug found in issue #3655
   264  func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
   265  	c := helm.NewContext()
   266  	rs := rsFixture()
   267  
   268  	installReq := &services.InstallReleaseRequest{
   269  		Namespace: "spaced",
   270  		Chart: &chart.Chart{
   271  			Metadata: &chart.Metadata{Name: "hello"},
   272  			Templates: []*chart.Template{
   273  				{Name: "templates/hello", Data: []byte("hello: world")},
   274  				{Name: "templates/hooks", Data: []byte(manifestWithHook)},
   275  			},
   276  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   277  		},
   278  		Values: &chart.Config{Raw: "foo: bar"},
   279  	}
   280  
   281  	fmt.Println("Running Install release with foo: bar override")
   282  	installResp, err := rs.InstallRelease(c, installReq)
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  
   287  	rel := installResp.Release
   288  	req := &services.UpdateReleaseRequest{
   289  		Name: rel.Name,
   290  		Chart: &chart.Chart{
   291  			Metadata: &chart.Metadata{Name: "hello"},
   292  			Templates: []*chart.Template{
   293  				{Name: "templates/hello", Data: []byte("hello: world")},
   294  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   295  			},
   296  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   297  		},
   298  	}
   299  
   300  	fmt.Println("Running Update release with no overrides and no reuse-values flag")
   301  	res, err := rs.UpdateRelease(c, req)
   302  	if err != nil {
   303  		t.Fatalf("Failed updated: %s", err)
   304  	}
   305  
   306  	expect := "foo: bar"
   307  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   308  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
   309  	}
   310  
   311  	rel = res.Release
   312  	req = &services.UpdateReleaseRequest{
   313  		Name: rel.Name,
   314  		Chart: &chart.Chart{
   315  			Metadata: &chart.Metadata{Name: "hello"},
   316  			Templates: []*chart.Template{
   317  				{Name: "templates/hello", Data: []byte("hello: world")},
   318  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   319  			},
   320  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   321  		},
   322  		Values:      &chart.Config{Raw: "foo2: bar2"},
   323  		ReuseValues: true,
   324  	}
   325  
   326  	fmt.Println("Running Update release with foo2: bar2 override and reuse-values")
   327  	res, err = rs.UpdateRelease(c, req)
   328  	if err != nil {
   329  		t.Fatalf("Failed updated: %s", err)
   330  	}
   331  
   332  	// This should have the newly-passed overrides.
   333  	expect = "foo: bar\nfoo2: bar2\n"
   334  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   335  		t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
   336  	}
   337  
   338  	rel = res.Release
   339  	req = &services.UpdateReleaseRequest{
   340  		Name: rel.Name,
   341  		Chart: &chart.Chart{
   342  			Metadata: &chart.Metadata{Name: "hello"},
   343  			Templates: []*chart.Template{
   344  				{Name: "templates/hello", Data: []byte("hello: world")},
   345  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   346  			},
   347  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   348  		},
   349  		Values:      &chart.Config{Raw: "foo: baz"},
   350  		ReuseValues: true,
   351  	}
   352  
   353  	fmt.Println("Running Update release with foo=baz override with reuse-values flag")
   354  	res, err = rs.UpdateRelease(c, req)
   355  	if err != nil {
   356  		t.Fatalf("Failed updated: %s", err)
   357  	}
   358  	expect = "foo: baz\nfoo2: bar2\n"
   359  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   360  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
   361  	}
   362  }
   363  
   364  func TestUpdateRelease_ReuseValues(t *testing.T) {
   365  	c := helm.NewContext()
   366  	rs := rsFixture()
   367  	rel := releaseStub()
   368  	rs.env.Releases.Create(rel)
   369  
   370  	req := &services.UpdateReleaseRequest{
   371  		Name: rel.Name,
   372  		Chart: &chart.Chart{
   373  			Metadata: &chart.Metadata{Name: "hello"},
   374  			Templates: []*chart.Template{
   375  				{Name: "templates/hello", Data: []byte("hello: world")},
   376  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   377  			},
   378  			// Since reuseValues is set, this should get ignored.
   379  			Values: &chart.Config{Raw: "foo: bar\n"},
   380  		},
   381  		Values:      &chart.Config{Raw: "name2: val2"},
   382  		ReuseValues: true,
   383  	}
   384  	res, err := rs.UpdateRelease(c, req)
   385  	if err != nil {
   386  		t.Fatalf("Failed updated: %s", err)
   387  	}
   388  	// This should have been overwritten with the old value.
   389  	expect := "name: value\n"
   390  	if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect {
   391  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw)
   392  	}
   393  	// This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub()
   394  	expect = "name: value\nname2: val2\n"
   395  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   396  		t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
   397  	}
   398  	compareStoredAndReturnedRelease(t, *rs, *res)
   399  }
   400  
   401  func TestUpdateRelease_ResetReuseValues(t *testing.T) {
   402  	// This verifies that when both reset and reuse are set, reset wins.
   403  	c := helm.NewContext()
   404  	rs := rsFixture()
   405  	rel := releaseStub()
   406  	rs.env.Releases.Create(rel)
   407  
   408  	req := &services.UpdateReleaseRequest{
   409  		Name: rel.Name,
   410  		Chart: &chart.Chart{
   411  			Metadata: &chart.Metadata{Name: "hello"},
   412  			Templates: []*chart.Template{
   413  				{Name: "templates/hello", Data: []byte("hello: world")},
   414  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   415  			},
   416  		},
   417  		ResetValues: true,
   418  		ReuseValues: true,
   419  	}
   420  	res, err := rs.UpdateRelease(c, req)
   421  	if err != nil {
   422  		t.Fatalf("Failed updated: %s", err)
   423  	}
   424  	// This should have been unset. Config:  &chart.Config{Raw: `name: value`},
   425  	if res.Release.Config != nil && res.Release.Config.Raw != "" {
   426  		t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
   427  	}
   428  	compareStoredAndReturnedRelease(t, *rs, *res)
   429  }
   430  
   431  func TestUpdateReleaseFailure(t *testing.T) {
   432  	c := helm.NewContext()
   433  	rs := rsFixture()
   434  	rel := releaseStub()
   435  	rs.env.Releases.Create(rel)
   436  	rs.env.KubeClient = newUpdateFailingKubeClient()
   437  	rs.Log = t.Logf
   438  
   439  	req := &services.UpdateReleaseRequest{
   440  		Name:         rel.Name,
   441  		DisableHooks: true,
   442  		Chart: &chart.Chart{
   443  			Metadata: &chart.Metadata{Name: "hello"},
   444  			Templates: []*chart.Template{
   445  				{Name: "templates/something", Data: []byte("hello: world")},
   446  			},
   447  		},
   448  	}
   449  
   450  	res, err := rs.UpdateRelease(c, req)
   451  	if err == nil {
   452  		t.Error("Expected failed update")
   453  	}
   454  
   455  	if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_FAILED {
   456  		t.Errorf("Expected FAILED release. Got %d", updatedStatus)
   457  	}
   458  
   459  	compareStoredAndReturnedRelease(t, *rs, *res)
   460  
   461  	expectedDescription := "Upgrade \"angry-panda\" failed: Failed update in kube client"
   462  	if got := res.Release.Info.Description; got != expectedDescription {
   463  		t.Errorf("Expected description %q, got %q", expectedDescription, got)
   464  	}
   465  
   466  	oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version)
   467  	if err != nil {
   468  		t.Errorf("Expected to be able to get previous release")
   469  	}
   470  	if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DEPLOYED {
   471  		t.Errorf("Expected Deployed status on previous Release version. Got %v", oldStatus)
   472  	}
   473  }
   474  
   475  func TestUpdateReleaseFailure_Force(t *testing.T) {
   476  	c := helm.NewContext()
   477  	rs := rsFixture()
   478  	rel := namedReleaseStub("forceful-luke", release.Status_FAILED)
   479  	rs.env.Releases.Create(rel)
   480  	rs.Log = t.Logf
   481  
   482  	req := &services.UpdateReleaseRequest{
   483  		Name:         rel.Name,
   484  		DisableHooks: true,
   485  		Chart: &chart.Chart{
   486  			Metadata: &chart.Metadata{Name: "hello"},
   487  			Templates: []*chart.Template{
   488  				{Name: "templates/something", Data: []byte("text: 'Did you ever hear the tragedy of Darth Plagueis the Wise? I thought not. It’s not a story the Jedi would tell you. It’s a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and so wise he could use the Force to influence the Midichlorians to create life... He had such a knowledge of the Dark Side that he could even keep the ones he cared about from dying. The Dark Side of the Force is a pathway to many abilities some consider to be unnatural. He became so powerful... The only thing he was afraid of was losing his power, which eventually, of course, he did. Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep. Ironic. He could save others from death, but not himself.'")},
   489  			},
   490  		},
   491  		Force: true,
   492  	}
   493  
   494  	res, err := rs.UpdateRelease(c, req)
   495  	if err != nil {
   496  		t.Errorf("Expected successful update, got %v", err)
   497  	}
   498  
   499  	if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_DEPLOYED {
   500  		t.Errorf("Expected DEPLOYED release. Got %d", updatedStatus)
   501  	}
   502  
   503  	compareStoredAndReturnedRelease(t, *rs, *res)
   504  
   505  	expectedDescription := "Upgrade complete"
   506  	if got := res.Release.Info.Description; got != expectedDescription {
   507  		t.Errorf("Expected description %q, got %q", expectedDescription, got)
   508  	}
   509  
   510  	oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version)
   511  	if err != nil {
   512  		t.Errorf("Expected to be able to get previous release")
   513  	}
   514  	if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DELETED {
   515  		t.Errorf("Expected Deleted status on previous Release version. Got %v", oldStatus)
   516  	}
   517  }
   518  
   519  func TestUpdateReleaseNoHooks(t *testing.T) {
   520  	c := helm.NewContext()
   521  	rs := rsFixture()
   522  	rel := releaseStub()
   523  	rs.env.Releases.Create(rel)
   524  
   525  	req := &services.UpdateReleaseRequest{
   526  		Name:         rel.Name,
   527  		DisableHooks: true,
   528  		Chart: &chart.Chart{
   529  			Metadata: &chart.Metadata{Name: "hello"},
   530  			Templates: []*chart.Template{
   531  				{Name: "templates/hello", Data: []byte("hello: world")},
   532  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   533  			},
   534  		},
   535  	}
   536  
   537  	res, err := rs.UpdateRelease(c, req)
   538  	if err != nil {
   539  		t.Fatalf("Failed updated: %s", err)
   540  	}
   541  
   542  	if hl := res.Release.Hooks[0].LastRun; hl != nil {
   543  		t.Errorf("Expected that no hooks were run. Got %d", hl)
   544  	}
   545  
   546  }
   547  
   548  func TestUpdateReleaseNoChanges(t *testing.T) {
   549  	c := helm.NewContext()
   550  	rs := rsFixture()
   551  	rel := releaseStub()
   552  	rs.env.Releases.Create(rel)
   553  
   554  	req := &services.UpdateReleaseRequest{
   555  		Name:         rel.Name,
   556  		DisableHooks: true,
   557  		Chart:        rel.GetChart(),
   558  	}
   559  
   560  	_, err := rs.UpdateRelease(c, req)
   561  	if err != nil {
   562  		t.Fatalf("Failed updated: %s", err)
   563  	}
   564  }
   565  
   566  func TestUpdateReleaseCustomDescription(t *testing.T) {
   567  	c := helm.NewContext()
   568  	rs := rsFixture()
   569  	rel := releaseStub()
   570  	rs.env.Releases.Create(rel)
   571  
   572  	customDescription := "foo"
   573  
   574  	req := &services.UpdateReleaseRequest{
   575  		Name:        rel.Name,
   576  		Chart:       rel.GetChart(),
   577  		Description: customDescription,
   578  	}
   579  
   580  	res, err := rs.UpdateRelease(c, req)
   581  	if err != nil {
   582  		t.Fatalf("Failed updated: %s", err)
   583  	}
   584  	if res.Release.Info.Description != customDescription {
   585  		t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description)
   586  	}
   587  	compareStoredAndReturnedRelease(t, *rs, *res)
   588  }
   589  
   590  func TestUpdateReleaseCustomDescription_Force(t *testing.T) {
   591  	c := helm.NewContext()
   592  	rs := rsFixture()
   593  	rel := releaseStub()
   594  	rs.env.Releases.Create(rel)
   595  
   596  	customDescription := "foo"
   597  
   598  	req := &services.UpdateReleaseRequest{
   599  		Name:        rel.Name,
   600  		Chart:       rel.GetChart(),
   601  		Force:       true,
   602  		Description: customDescription,
   603  	}
   604  
   605  	res, err := rs.UpdateRelease(c, req)
   606  	if err != nil {
   607  		t.Fatalf("Failed updated: %s", err)
   608  	}
   609  	if res.Release.Info.Description != customDescription {
   610  		t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description)
   611  	}
   612  	compareStoredAndReturnedRelease(t, *rs, *res)
   613  }
   614  
   615  func TestUpdateReleasePendingInstall_Force(t *testing.T) {
   616  	c := helm.NewContext()
   617  	rs := rsFixture()
   618  	rel := namedReleaseStub("forceful-luke", release.Status_PENDING_INSTALL)
   619  	rs.env.Releases.Create(rel)
   620  
   621  	req := &services.UpdateReleaseRequest{
   622  		Name:  rel.Name,
   623  		Chart: rel.GetChart(),
   624  		Force: true,
   625  	}
   626  
   627  	_, err := rs.UpdateRelease(c, req)
   628  	if err == nil {
   629  		t.Error("Expected failed update")
   630  	}
   631  
   632  	expectedError := "a release named forceful-luke is in use, cannot re-use a name that is still in use"
   633  	got := err.Error()
   634  	if err.Error() != expectedError {
   635  		t.Errorf("Expected error %q, got %q", expectedError, got)
   636  	}
   637  }
   638  
   639  func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release {
   640  	storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
   641  	if err != nil {
   642  		t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
   643  	}
   644  
   645  	if !proto.Equal(storedRelease, res.Release) {
   646  		t.Errorf("Stored release doesn't match returned Release")
   647  	}
   648  
   649  	return storedRelease
   650  }