github.com/Beeketing/helm@v2.12.1+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  	"strings"
    22  	"testing"
    23  
    24  	"github.com/golang/protobuf/proto"
    25  
    26  	"k8s.io/helm/pkg/chartutil"
    27  	"k8s.io/helm/pkg/helm"
    28  	"k8s.io/helm/pkg/proto/hapi/chart"
    29  	"k8s.io/helm/pkg/proto/hapi/release"
    30  	"k8s.io/helm/pkg/proto/hapi/services"
    31  	"reflect"
    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 TestUpdateRelease_ResetValues(t *testing.T) {
   108  	c := helm.NewContext()
   109  	rs := rsFixture()
   110  	rel := releaseStub()
   111  	rs.env.Releases.Create(rel)
   112  
   113  	req := &services.UpdateReleaseRequest{
   114  		Name: rel.Name,
   115  		Chart: &chart.Chart{
   116  			Metadata: &chart.Metadata{Name: "hello"},
   117  			Templates: []*chart.Template{
   118  				{Name: "templates/hello", Data: []byte("hello: world")},
   119  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   120  			},
   121  		},
   122  		ResetValues: true,
   123  	}
   124  	res, err := rs.UpdateRelease(c, req)
   125  	if err != nil {
   126  		t.Fatalf("Failed updated: %s", err)
   127  	}
   128  	// This should have been unset. Config:  &chart.Config{Raw: `name: value`},
   129  	if res.Release.Config != nil && res.Release.Config.Raw != "" {
   130  		t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
   131  	}
   132  }
   133  
   134  func TestUpdateRelease_ReuseValuesWithNoValues(t *testing.T) {
   135  	c := helm.NewContext()
   136  	rs := rsFixture()
   137  
   138  	installReq := &services.InstallReleaseRequest{
   139  		Namespace: "spaced",
   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(manifestWithHook)},
   145  			},
   146  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   147  		},
   148  	}
   149  
   150  	installResp, err := rs.InstallRelease(c, installReq)
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  
   155  	rel := installResp.Release
   156  	req := &services.UpdateReleaseRequest{
   157  		Name: rel.Name,
   158  		Chart: &chart.Chart{
   159  			Metadata: &chart.Metadata{Name: "hello"},
   160  			Templates: []*chart.Template{
   161  				{Name: "templates/hello", Data: []byte("hello: world")},
   162  			},
   163  		},
   164  		Values:      &chart.Config{Raw: "{}\n"},
   165  		ReuseValues: true,
   166  	}
   167  
   168  	if _, err := rs.UpdateRelease(c, req); err != nil {
   169  		t.Fatalf("Failed updated: %s", err)
   170  	}
   171  }
   172  
   173  func TestUpdateRelease_NestedReuseValues(t *testing.T) {
   174  	c := helm.NewContext()
   175  	rs := rsFixture()
   176  
   177  	installReq := &services.InstallReleaseRequest{
   178  		Namespace: "spaced",
   179  		Chart: &chart.Chart{
   180  			Metadata: &chart.Metadata{Name: "hello"},
   181  			Templates: []*chart.Template{
   182  				{Name: "templates/hello", Data: []byte("hello: world")},
   183  			},
   184  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   185  		},
   186  		Values: &chart.Config{Raw: `
   187  foo: bar
   188  root:
   189    nested: nestedValue
   190    anotherNested: anotherNestedValue
   191  `},
   192  	}
   193  
   194  	installResp, err := rs.InstallRelease(c, installReq)
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  
   199  	rel := installResp.Release
   200  	req := &services.UpdateReleaseRequest{
   201  		Name: rel.Name,
   202  		Chart: &chart.Chart{
   203  			Metadata: &chart.Metadata{Name: "hello"},
   204  			Templates: []*chart.Template{
   205  				{Name: "templates/hello", Data: []byte("hello: world")},
   206  			},
   207  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   208  		},
   209  		Values: &chart.Config{Raw: `
   210  root:
   211    nested: newNestedValue
   212  `},
   213  		ReuseValues: true,
   214  	}
   215  
   216  	res, err := rs.UpdateRelease(c, req)
   217  	if err != nil {
   218  		t.Fatalf("Failed updated: %s", err)
   219  	}
   220  
   221  	expect, _ := chartutil.ReadValues([]byte(`
   222  foo: bar
   223  root:
   224    nested: newNestedValue
   225    anotherNested: anotherNestedValue
   226  `))
   227  
   228  	requestConfig, err := chartutil.ReadValues([]byte(res.Release.Config.Raw))
   229  	if err != nil {
   230  		t.Errorf("Request config could not be parsed: %v", err)
   231  	}
   232  
   233  	if !reflect.DeepEqual(expect, requestConfig) {
   234  		t.Errorf("Expected request config to be %v, got %v", expect, requestConfig)
   235  	}
   236  }
   237  
   238  // This is a regression test for bug found in issue #3655
   239  func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
   240  	c := helm.NewContext()
   241  	rs := rsFixture()
   242  
   243  	installReq := &services.InstallReleaseRequest{
   244  		Namespace: "spaced",
   245  		Chart: &chart.Chart{
   246  			Metadata: &chart.Metadata{Name: "hello"},
   247  			Templates: []*chart.Template{
   248  				{Name: "templates/hello", Data: []byte("hello: world")},
   249  				{Name: "templates/hooks", Data: []byte(manifestWithHook)},
   250  			},
   251  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   252  		},
   253  		Values: &chart.Config{Raw: "foo: bar"},
   254  	}
   255  
   256  	fmt.Println("Running Install release with foo: bar override")
   257  	installResp, err := rs.InstallRelease(c, installReq)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	rel := installResp.Release
   263  	req := &services.UpdateReleaseRequest{
   264  		Name: rel.Name,
   265  		Chart: &chart.Chart{
   266  			Metadata: &chart.Metadata{Name: "hello"},
   267  			Templates: []*chart.Template{
   268  				{Name: "templates/hello", Data: []byte("hello: world")},
   269  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   270  			},
   271  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   272  		},
   273  	}
   274  
   275  	fmt.Println("Running Update release with no overrides and no reuse-values flag")
   276  	res, err := rs.UpdateRelease(c, req)
   277  	if err != nil {
   278  		t.Fatalf("Failed updated: %s", err)
   279  	}
   280  
   281  	expect := "foo: bar"
   282  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   283  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
   284  	}
   285  
   286  	rel = res.Release
   287  	req = &services.UpdateReleaseRequest{
   288  		Name: rel.Name,
   289  		Chart: &chart.Chart{
   290  			Metadata: &chart.Metadata{Name: "hello"},
   291  			Templates: []*chart.Template{
   292  				{Name: "templates/hello", Data: []byte("hello: world")},
   293  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   294  			},
   295  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   296  		},
   297  		Values:      &chart.Config{Raw: "foo2: bar2"},
   298  		ReuseValues: true,
   299  	}
   300  
   301  	fmt.Println("Running Update release with foo2: bar2 override and reuse-values")
   302  	res, err = rs.UpdateRelease(c, req)
   303  	if err != nil {
   304  		t.Fatalf("Failed updated: %s", err)
   305  	}
   306  
   307  	// This should have the newly-passed overrides.
   308  	expect = "foo: bar\nfoo2: bar2\n"
   309  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   310  		t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
   311  	}
   312  
   313  	rel = res.Release
   314  	req = &services.UpdateReleaseRequest{
   315  		Name: rel.Name,
   316  		Chart: &chart.Chart{
   317  			Metadata: &chart.Metadata{Name: "hello"},
   318  			Templates: []*chart.Template{
   319  				{Name: "templates/hello", Data: []byte("hello: world")},
   320  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   321  			},
   322  			Values: &chart.Config{Raw: "defaultFoo: defaultBar"},
   323  		},
   324  		Values:      &chart.Config{Raw: "foo: baz"},
   325  		ReuseValues: true,
   326  	}
   327  
   328  	fmt.Println("Running Update release with foo=baz override with reuse-values flag")
   329  	res, err = rs.UpdateRelease(c, req)
   330  	if err != nil {
   331  		t.Fatalf("Failed updated: %s", err)
   332  	}
   333  	expect = "foo: baz\nfoo2: bar2\n"
   334  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   335  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
   336  	}
   337  }
   338  
   339  func TestUpdateRelease_ReuseValues(t *testing.T) {
   340  	c := helm.NewContext()
   341  	rs := rsFixture()
   342  	rel := releaseStub()
   343  	rs.env.Releases.Create(rel)
   344  
   345  	req := &services.UpdateReleaseRequest{
   346  		Name: rel.Name,
   347  		Chart: &chart.Chart{
   348  			Metadata: &chart.Metadata{Name: "hello"},
   349  			Templates: []*chart.Template{
   350  				{Name: "templates/hello", Data: []byte("hello: world")},
   351  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   352  			},
   353  			// Since reuseValues is set, this should get ignored.
   354  			Values: &chart.Config{Raw: "foo: bar\n"},
   355  		},
   356  		Values:      &chart.Config{Raw: "name2: val2"},
   357  		ReuseValues: true,
   358  	}
   359  	res, err := rs.UpdateRelease(c, req)
   360  	if err != nil {
   361  		t.Fatalf("Failed updated: %s", err)
   362  	}
   363  	// This should have been overwritten with the old value.
   364  	expect := "name: value\n"
   365  	if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect {
   366  		t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw)
   367  	}
   368  	// This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub()
   369  	expect = "name: value\nname2: val2\n"
   370  	if res.Release.Config != nil && res.Release.Config.Raw != expect {
   371  		t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
   372  	}
   373  	compareStoredAndReturnedRelease(t, *rs, *res)
   374  }
   375  
   376  func TestUpdateRelease_ResetReuseValues(t *testing.T) {
   377  	// This verifies that when both reset and reuse are set, reset wins.
   378  	c := helm.NewContext()
   379  	rs := rsFixture()
   380  	rel := releaseStub()
   381  	rs.env.Releases.Create(rel)
   382  
   383  	req := &services.UpdateReleaseRequest{
   384  		Name: rel.Name,
   385  		Chart: &chart.Chart{
   386  			Metadata: &chart.Metadata{Name: "hello"},
   387  			Templates: []*chart.Template{
   388  				{Name: "templates/hello", Data: []byte("hello: world")},
   389  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   390  			},
   391  		},
   392  		ResetValues: true,
   393  		ReuseValues: true,
   394  	}
   395  	res, err := rs.UpdateRelease(c, req)
   396  	if err != nil {
   397  		t.Fatalf("Failed updated: %s", err)
   398  	}
   399  	// This should have been unset. Config:  &chart.Config{Raw: `name: value`},
   400  	if res.Release.Config != nil && res.Release.Config.Raw != "" {
   401  		t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
   402  	}
   403  	compareStoredAndReturnedRelease(t, *rs, *res)
   404  }
   405  
   406  func TestUpdateReleaseFailure(t *testing.T) {
   407  	c := helm.NewContext()
   408  	rs := rsFixture()
   409  	rel := releaseStub()
   410  	rs.env.Releases.Create(rel)
   411  	rs.env.KubeClient = newUpdateFailingKubeClient()
   412  	rs.Log = t.Logf
   413  
   414  	req := &services.UpdateReleaseRequest{
   415  		Name:         rel.Name,
   416  		DisableHooks: true,
   417  		Chart: &chart.Chart{
   418  			Metadata: &chart.Metadata{Name: "hello"},
   419  			Templates: []*chart.Template{
   420  				{Name: "templates/something", Data: []byte("hello: world")},
   421  			},
   422  		},
   423  	}
   424  
   425  	res, err := rs.UpdateRelease(c, req)
   426  	if err == nil {
   427  		t.Error("Expected failed update")
   428  	}
   429  
   430  	if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_FAILED {
   431  		t.Errorf("Expected FAILED release. Got %d", updatedStatus)
   432  	}
   433  
   434  	compareStoredAndReturnedRelease(t, *rs, *res)
   435  
   436  	expectedDescription := "Upgrade \"angry-panda\" failed: Failed update in kube client"
   437  	if got := res.Release.Info.Description; got != expectedDescription {
   438  		t.Errorf("Expected description %q, got %q", expectedDescription, got)
   439  	}
   440  
   441  	oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version)
   442  	if err != nil {
   443  		t.Errorf("Expected to be able to get previous release")
   444  	}
   445  	if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DEPLOYED {
   446  		t.Errorf("Expected Deployed status on previous Release version. Got %v", oldStatus)
   447  	}
   448  }
   449  
   450  func TestUpdateReleaseFailure_Force(t *testing.T) {
   451  	c := helm.NewContext()
   452  	rs := rsFixture()
   453  	rel := namedReleaseStub("forceful-luke", release.Status_FAILED)
   454  	rs.env.Releases.Create(rel)
   455  	rs.Log = t.Logf
   456  
   457  	req := &services.UpdateReleaseRequest{
   458  		Name:         rel.Name,
   459  		DisableHooks: true,
   460  		Chart: &chart.Chart{
   461  			Metadata: &chart.Metadata{Name: "hello"},
   462  			Templates: []*chart.Template{
   463  				{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.'")},
   464  			},
   465  		},
   466  		Force: true,
   467  	}
   468  
   469  	res, err := rs.UpdateRelease(c, req)
   470  	if err != nil {
   471  		t.Errorf("Expected successful update, got %v", err)
   472  	}
   473  
   474  	if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_DEPLOYED {
   475  		t.Errorf("Expected DEPLOYED release. Got %d", updatedStatus)
   476  	}
   477  
   478  	compareStoredAndReturnedRelease(t, *rs, *res)
   479  
   480  	expectedDescription := "Upgrade complete"
   481  	if got := res.Release.Info.Description; got != expectedDescription {
   482  		t.Errorf("Expected description %q, got %q", expectedDescription, got)
   483  	}
   484  
   485  	oldRelease, err := rs.env.Releases.Get(rel.Name, rel.Version)
   486  	if err != nil {
   487  		t.Errorf("Expected to be able to get previous release")
   488  	}
   489  	if oldStatus := oldRelease.Info.Status.Code; oldStatus != release.Status_DELETED {
   490  		t.Errorf("Expected Deleted status on previous Release version. Got %v", oldStatus)
   491  	}
   492  }
   493  
   494  func TestUpdateReleaseNoHooks(t *testing.T) {
   495  	c := helm.NewContext()
   496  	rs := rsFixture()
   497  	rel := releaseStub()
   498  	rs.env.Releases.Create(rel)
   499  
   500  	req := &services.UpdateReleaseRequest{
   501  		Name:         rel.Name,
   502  		DisableHooks: true,
   503  		Chart: &chart.Chart{
   504  			Metadata: &chart.Metadata{Name: "hello"},
   505  			Templates: []*chart.Template{
   506  				{Name: "templates/hello", Data: []byte("hello: world")},
   507  				{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
   508  			},
   509  		},
   510  	}
   511  
   512  	res, err := rs.UpdateRelease(c, req)
   513  	if err != nil {
   514  		t.Fatalf("Failed updated: %s", err)
   515  	}
   516  
   517  	if hl := res.Release.Hooks[0].LastRun; hl != nil {
   518  		t.Errorf("Expected that no hooks were run. Got %d", hl)
   519  	}
   520  
   521  }
   522  
   523  func TestUpdateReleaseNoChanges(t *testing.T) {
   524  	c := helm.NewContext()
   525  	rs := rsFixture()
   526  	rel := releaseStub()
   527  	rs.env.Releases.Create(rel)
   528  
   529  	req := &services.UpdateReleaseRequest{
   530  		Name:         rel.Name,
   531  		DisableHooks: true,
   532  		Chart:        rel.GetChart(),
   533  	}
   534  
   535  	_, err := rs.UpdateRelease(c, req)
   536  	if err != nil {
   537  		t.Fatalf("Failed updated: %s", err)
   538  	}
   539  }
   540  
   541  func TestUpdateReleaseCustomDescription(t *testing.T) {
   542  	c := helm.NewContext()
   543  	rs := rsFixture()
   544  	rel := releaseStub()
   545  	rs.env.Releases.Create(rel)
   546  
   547  	customDescription := "foo"
   548  
   549  	req := &services.UpdateReleaseRequest{
   550  		Name:        rel.Name,
   551  		Chart:       rel.GetChart(),
   552  		Description: customDescription,
   553  	}
   554  
   555  	res, err := rs.UpdateRelease(c, req)
   556  	if err != nil {
   557  		t.Fatalf("Failed updated: %s", err)
   558  	}
   559  	if res.Release.Info.Description != customDescription {
   560  		t.Errorf("Expected release description to be %q, got %q", customDescription, res.Release.Info.Description)
   561  	}
   562  	compareStoredAndReturnedRelease(t, *rs, *res)
   563  }
   564  
   565  func TestUpdateReleaseCustomDescription_Force(t *testing.T) {
   566  	c := helm.NewContext()
   567  	rs := rsFixture()
   568  	rel := releaseStub()
   569  	rs.env.Releases.Create(rel)
   570  
   571  	customDescription := "foo"
   572  
   573  	req := &services.UpdateReleaseRequest{
   574  		Name:        rel.Name,
   575  		Chart:       rel.GetChart(),
   576  		Force:       true,
   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 TestUpdateReleasePendingInstall_Force(t *testing.T) {
   591  	c := helm.NewContext()
   592  	rs := rsFixture()
   593  	rel := namedReleaseStub("forceful-luke", release.Status_PENDING_INSTALL)
   594  	rs.env.Releases.Create(rel)
   595  
   596  	req := &services.UpdateReleaseRequest{
   597  		Name:  rel.Name,
   598  		Chart: rel.GetChart(),
   599  		Force: true,
   600  	}
   601  
   602  	_, err := rs.UpdateRelease(c, req)
   603  	if err == nil {
   604  		t.Error("Expected failed update")
   605  	}
   606  
   607  	expectedError := "a released named forceful-luke is in use, cannot re-use a name that is still in use"
   608  	got := err.Error()
   609  	if err.Error() != expectedError {
   610  		t.Errorf("Expected error %q, got %q", expectedError, got)
   611  	}
   612  }
   613  
   614  func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release {
   615  	storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
   616  	if err != nil {
   617  		t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
   618  	}
   619  
   620  	if !proto.Equal(storedRelease, res.Release) {
   621  		t.Errorf("Stored release doesn't match returned Release")
   622  	}
   623  
   624  	return storedRelease
   625  }