Repository: helm/helm (go)

Issue:
a failed `lookup` removes all rendered output
After testing the `lookup` function introduced in #6752, I found calling `lookup` in a template caused the rendered output to be empty.

Here's what I used to test. After creating a new chart with `helm create foo`, I modified `foo/templates/deployment.yaml` to add a new label that performs a lookup:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "foo.fullname" . }}
  labels:
    foo: {{ (lookup "v1" "Deployment" .Release.Namespace "nginx").metadata.name }}
...
```

And then created a deployment to match that lookup:

```
><> kubectl run nginx --image=nginx --replicas=5
deployment.apps/nginx created
```

No output is rendered.

```
><> ./bin/helm template --validate ./foo/

><> ./bin/helm version
version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"9c680e604be8d516960eecbbc3718ace91643cea", GitTreeState:"dirty", GoVersion:"go1.13.6"}
```

Calling `helm install` fails to render, as no objects were rendered.

```
><> ./bin/helm install foo ./foo/
Error: no objects visited
```

I will look further into this, but @raffaelespazzoli, can you please look further into this and see where the issue may be stemming from?

Pull request:
fix(lookup_func): do not return error when object is not found
closes #7473.

Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>

Patch:
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index c84a6f866..000000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Helm Security Reporting and Policy
-
-The Helm project has [a common process and policy that can be found here](https://github.com/helm/community/blob/master/SECURITY.md).
\ No newline at end of file
diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go
index 1601cb448..a44140d9f 100644
--- a/cmd/helm/completion.go
+++ b/cmd/helm/completion.go
@@ -139,10 +139,7 @@ __helm_compgen() {
 	fi
 	for w in "${completions[@]}"; do
 		if [[ "${w}" = "$1"* ]]; then
-			# Use printf instead of echo beause it is possible that
-			# the value to print is -n, which would be interpreted
-			# as a flag to echo
-			printf "%s\n" "${w}"
+			echo "${w}"
 		fi
 	done
 }
diff --git a/cmd/helm/package.go b/cmd/helm/package.go
index 00fe0ef11..20cde6e4c 100644
--- a/cmd/helm/package.go
+++ b/cmd/helm/package.go
@@ -118,6 +118,7 @@ func newPackageCmd(out io.Writer) *cobra.Command {
 	f.StringVar(&client.AppVersion, "app-version", "", "set the appVersion on the chart to this version")
 	f.StringVarP(&client.Destination, "destination", "d", ".", "location to write the chart.")
 	f.BoolVarP(&client.DependencyUpdate, "dependency-update", "u", false, `update dependencies from "Chart.yaml" to dir "charts/" before packaging`)
+	addValueOptionsFlags(f, valueOpts)
 
 	return cmd
 }
diff --git a/cmd/helm/template.go b/cmd/helm/template.go
index dc62c6e95..1c34d7245 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -112,9 +112,9 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 					if missing {
 						return fmt.Errorf("could not find template %s in chart", f)
 					}
-				}
-				for _, m := range manifestsToRender {
-					fmt.Fprintf(out, "---\n%s\n", m)
+					for _, m := range manifestsToRender {
+						fmt.Fprintf(out, "---\n%s\n", m)
+					}
 				}
 			} else {
 				fmt.Fprintf(out, "%s", manifests.String())
diff --git a/pkg/action/list.go b/pkg/action/list.go
index 5be60ac42..5d3417203 100644
--- a/pkg/action/list.go
+++ b/pkg/action/list.go
@@ -26,7 +26,7 @@ import (
 
 // ListStates represents zero or more status codes that a list item may have set
 //
-// Because this is used as a bitmask filter, more than one bit can be flipped
+// Because this is used as a bitmask filter, more than one one bit can be flipped
 // in the ListStates.
 type ListStates uint
 
diff --git a/pkg/action/package.go b/pkg/action/package.go
index b48fc65f0..5c85ebe0d 100644
--- a/pkg/action/package.go
+++ b/pkg/action/package.go
@@ -60,6 +60,12 @@ func (p *Package) Run(path string, vals map[string]interface{}) (string, error)
 		return "", err
 	}
 
+	combinedVals, err := chartutil.CoalesceValues(ch, vals)
+	if err != nil {
+		return "", err
+	}
+	ch.Values = combinedVals
+
 	// If version is set, modify the version.
 	if p.Version != "" {
 		if err := setVersion(ch, p.Version); err != nil {
diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go
index 1db4184ff..cdc40eaaa 100644
--- a/pkg/action/upgrade.go
+++ b/pkg/action/upgrade.go
@@ -291,7 +291,7 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
 	rel.Info.Status = release.StatusFailed
 	rel.Info.Description = msg
 	u.cfg.recordRelease(rel)
-	if u.CleanupOnFail && len(created) > 0 {
+	if u.CleanupOnFail {
 		u.cfg.Log("Cleanup on fail set, cleaning up %d resources", len(created))
 		_, errs := u.cfg.KubeClient.Delete(created)
 		if errs != nil {
diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go
index 5eb4d4d94..c3e99eae6 100644
--- a/pkg/chart/chart.go
+++ b/pkg/chart/chart.go
@@ -33,7 +33,7 @@ type Chart struct {
 	Raw []*File `json:"-"`
 	// Metadata is the contents of the Chartfile.
 	Metadata *Metadata `json:"metadata"`
-	// Lock is the contents of Chart.lock.
+	// LocK is the contents of Chart.lock.
 	Lock *Lock `json:"lock"`
 	// Templates for this chart.
 	Templates []*File `json:"templates"`
diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go
index be0dfdc24..fb985bb59 100644
--- a/pkg/chartutil/save.go
+++ b/pkg/chartutil/save.go
@@ -50,12 +50,11 @@ func SaveDir(c *chart.Chart, dest string) error {
 	}
 
 	// Save values.yaml
-	for _, f := range c.Raw {
-		if f.Name == ValuesfileName {
-			vf := filepath.Join(outdir, ValuesfileName)
-			if err := writeFile(vf, f.Data); err != nil {
-				return err
-			}
+	if c.Values != nil {
+		vf := filepath.Join(outdir, ValuesfileName)
+		b, _ := yaml.Marshal(c.Values)
+		if err := writeFile(vf, b); err != nil {
+			return err
 		}
 	}
 
@@ -162,12 +161,12 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
 	}
 
 	// Save values.yaml
-	for _, f := range c.Raw {
-		if f.Name == ValuesfileName {
-			if err := writeToTar(out, filepath.Join(base, ValuesfileName), f.Data); err != nil {
-				return err
-			}
-		}
+	ydata, err := yaml.Marshal(c.Values)
+	if err != nil {
+		return err
+	}
+	if err := writeToTar(out, filepath.Join(base, ValuesfileName), ydata); err != nil {
+		return err
 	}
 
 	// Save values.schema.json if it exists
diff --git a/pkg/engine/lookup_func.go b/pkg/engine/lookup_func.go
index 14f2351b4..5dde29443 100644
--- a/pkg/engine/lookup_func.go
+++ b/pkg/engine/lookup_func.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/discovery"
@@ -30,6 +31,8 @@ import (
 
 type lookupFunc = func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error)
 
+// NewLookupFunction returns a function for looking up objects in the cluster. If the resource does not exist, no error
+// is raised.
 func NewLookupFunction(config *rest.Config) lookupFunc {
 	return func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error) {
 		var client dynamic.ResourceInterface
@@ -43,9 +46,14 @@ func NewLookupFunction(config *rest.Config) lookupFunc {
 			client = c
 		}
 		if name != "" {
-			//this will return a single object
+			// this will return a single object
 			obj, err := client.Get(name, metav1.GetOptions{})
 			if err != nil {
+				if apierrors.IsNotFound(err) {
+					// Just return an empty interface when the object was not found.
+					// That way, users can use `if not (lookup ...)` in their templates.
+					return map[string]interface{}{}, nil
+				}
 				return map[string]interface{}{}, err
 			}
 			return obj.UnstructuredContent(), nil
@@ -53,6 +61,11 @@ func NewLookupFunction(config *rest.Config) lookupFunc {
 		//this will return a list
 		obj, err := client.List(metav1.ListOptions{})
 		if err != nil {
+			if apierrors.IsNotFound(err) {
+				// Just return an empty interface when the object was not found.
+				// That way, users can use `if not (lookup ...)` in their templates.
+				return map[string]interface{}{}, nil
+			}
 			return map[string]interface{}{}, err
 		}
 		return obj.UnstructuredContent(), nil
diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go
index 68638c2ca..e11dbfcae 100644
--- a/pkg/getter/getter.go
+++ b/pkg/getter/getter.go
@@ -64,7 +64,7 @@ func WithUserAgent(userAgent string) Option {
 	}
 }
 
-// WithTLSClientConfig sets the client auth with the provided credentials.
+// WithTLSClientConfig sets the client client auth with the provided credentials.
 func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
 	return func(opts *options) {
 		opts.certFile = certFile
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index 3853e9036..adf195e34 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -21,6 +21,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"log"
 	"strings"
 	"sync"
 	"time"
@@ -420,7 +421,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object,
 		if err != nil {
 			return errors.Wrap(err, "failed to replace object")
 		}
-		c.Log("Replaced %q with kind %s for kind %s\n", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind)
+		log.Printf("Replaced %q with kind %s for kind %s\n", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind)
 	} else {
 		// send patch to server
 		obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)


Test patch:
diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go
index e0a5fabd6..38938b4af 100644
--- a/cmd/helm/package_test.go
+++ b/cmd/helm/package_test.go
@@ -17,9 +17,13 @@ package main
 
 import (
 	"bytes"
+	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
+	"runtime"
+	"strings"
 	"testing"
 
 	"github.com/spf13/cobra"
@@ -27,9 +31,15 @@ import (
 	"helm.sh/helm/v3/internal/test/ensure"
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chart/loader"
+	"helm.sh/helm/v3/pkg/chartutil"
 )
 
 func TestPackage(t *testing.T) {
+	statFileMsg := "no such file or directory"
+	if runtime.GOOS == "windows" {
+		statFileMsg = "The system cannot find the file specified."
+	}
+
 	tests := []struct {
 		name    string
 		flags   map[string]string
@@ -98,6 +108,13 @@ func TestPackage(t *testing.T) {
 			hasfile: "chart-missing-deps-0.1.0.tgz",
 			err:     true,
 		},
+		{
+			name:   "package --values does-not-exist",
+			args:   []string{"testdata/testcharts/alpine"},
+			flags:  map[string]string{"values": "does-not-exist"},
+			expect: fmt.Sprintf("does-not-exist: %s", statFileMsg),
+			err:    true,
+		},
 		{
 			name: "package testdata/testcharts/chart-bad-type",
 			args: []string{"testdata/testcharts/chart-bad-type"},
@@ -196,6 +213,159 @@ func TestSetAppVersion(t *testing.T) {
 	}
 }
 
+func TestPackageValues(t *testing.T) {
+	defer resetEnv()()
+
+	repoFile := "testdata/helmhome/helm/repositories.yaml"
+
+	testCases := []struct {
+		desc               string
+		args               []string
+		valuefilesContents []string
+		flags              map[string]string
+		expected           []string
+	}{
+		{
+			desc:               "helm package, single values file",
+			args:               []string{"testdata/testcharts/alpine"},
+			flags:              map[string]string{"repository-config": repoFile},
+			valuefilesContents: []string{"Name: chart-name-foo"},
+			expected:           []string{"Name: chart-name-foo"},
+		},
+		{
+			desc:               "helm package, multiple values files",
+			args:               []string{"testdata/testcharts/alpine"},
+			flags:              map[string]string{"repository-config": repoFile},
+			valuefilesContents: []string{"Name: chart-name-foo", "foo: bar"},
+			expected:           []string{"Name: chart-name-foo", "foo: bar"},
+		},
+		{
+			desc:     "helm package, with set option",
+			args:     []string{"testdata/testcharts/alpine"},
+			flags:    map[string]string{"set": "Name=chart-name-foo", "repository-config": repoFile},
+			expected: []string{"Name: chart-name-foo"},
+		},
+		{
+			desc:               "helm package, set takes precedence over value file",
+			args:               []string{"testdata/testcharts/alpine"},
+			valuefilesContents: []string{"Name: chart-name-foo"},
+			flags:              map[string]string{"set": "Name=chart-name-bar", "repository-config": repoFile},
+			expected:           []string{"Name: chart-name-bar"},
+		},
+	}
+
+	for _, tc := range testCases {
+		var files []string
+		for _, contents := range tc.valuefilesContents {
+			f := createValuesFile(t, contents)
+			files = append(files, f)
+		}
+		valueFiles := strings.Join(files, ",")
+
+		expected, err := chartutil.ReadValues([]byte(strings.Join(tc.expected, "\n")))
+		if err != nil {
+			t.Errorf("unexpected error parsing values: %q", err)
+		}
+
+		outputDir := ensure.TempDir(t)
+
+		if len(tc.flags) == 0 {
+			tc.flags = make(map[string]string)
+		}
+		tc.flags["destination"] = outputDir
+
+		if len(valueFiles) > 0 {
+			tc.flags["values"] = valueFiles
+		}
+
+		cmd := newPackageCmd(&bytes.Buffer{})
+		setFlags(cmd, tc.flags)
+		if err := cmd.RunE(cmd, tc.args); err != nil {
+			t.Fatalf("unexpected error: %q", err)
+		}
+
+		outputFile := filepath.Join(outputDir, "alpine-0.1.0.tgz")
+		verifyOutputChartExists(t, outputFile)
+
+		actual, err := getChartValues(outputFile)
+		if err != nil {
+			t.Fatalf("unexpected error extracting chart values: %q", err)
+		}
+
+		verifyValues(t, actual, expected)
+	}
+}
+
+func TestNonExistentDirAndBadPermission(t *testing.T) {
+	nonExistentDir := "testdata/testcharts/non-existent-directory"
+
+	tests := []struct {
+		name    string
+		flags   map[string]string
+		args    []string
+		expect  string
+		hasfile string
+		err     bool
+	}{
+		{
+			name:   "package testdata/testcharts/non-existent-directory",
+			args:   []string{"testdata/testcharts/non-existent-directory"},
+			expect: fmt.Sprintf("stat %s: no such file or directory", nonExistentDir),
+			err:    true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			var buf bytes.Buffer
+			c := newPackageCmd(&buf)
+			re := regexp.MustCompile(tt.expect)
+			err := c.RunE(c, tt.args)
+			if err != nil {
+				if tt.err && re.MatchString(err.Error()) {
+					return
+				}
+				t.Fatalf("%q: expected error %q, got %q", tt.name, tt.expect, err)
+			}
+		})
+	}
+}
+
+func createValuesFile(t *testing.T, data string) string {
+	outputDir := ensure.TempDir(t)
+
+	outputFile := filepath.Join(outputDir, "values.yaml")
+	if err := ioutil.WriteFile(outputFile, []byte(data), 0644); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	return outputFile
+}
+
+func getChartValues(chartPath string) (chartutil.Values, error) {
+	chart, err := loader.Load(chartPath)
+	if err != nil {
+		return nil, err
+	}
+	return chart.Values, nil
+}
+
+func verifyValues(t *testing.T, actual, expected chartutil.Values) {
+	t.Helper()
+	for key, value := range expected.AsMap() {
+		if got := actual[key]; got != value {
+			t.Errorf("Expected %q, got %q (%v)", value, got, actual)
+		}
+	}
+}
+
+func verifyOutputChartExists(t *testing.T, chartPath string) {
+	if chartFile, err := os.Stat(chartPath); err != nil {
+		t.Errorf("expected file %q, got err %q", chartPath, err)
+	} else if chartFile.Size() == 0 {
+		t.Errorf("file %q has zero bytes.", chartPath)
+	}
+}
+
 func setFlags(cmd *cobra.Command, flags map[string]string) {
 	dest := cmd.Flags()
 	for f, v := range flags {
diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go
index dc7987d01..35a8e996b 100644
--- a/cmd/helm/template_test.go
+++ b/cmd/helm/template_test.go
@@ -84,16 +84,6 @@ func TestTemplateCmd(t *testing.T) {
 			cmd:    fmt.Sprintf("template '%s' --include-crds", chartPath),
 			golden: "output/template-with-crds.txt",
 		},
-		{
-			name:   "template with show-only one",
-			cmd:    fmt.Sprintf("template '%s' --show-only templates/service.yaml", chartPath),
-			golden: "output/template-show-only-one.txt",
-		},
-		{
-			name:   "template with show-only multiple",
-			cmd:    fmt.Sprintf("template '%s' --show-only templates/service.yaml --show-only charts/subcharta/templates/service.yaml", chartPath),
-			golden: "output/template-show-only-multiple.txt",
-		},
 		{
 			name:   "sorted output of manifests (order of filenames, then order of objects within each YAML file)",
 			cmd:    fmt.Sprintf("template '%s'", "testdata/testcharts/object-order"),
diff --git a/cmd/helm/testdata/output/template-show-only-multiple.txt b/cmd/helm/testdata/output/template-show-only-multiple.txt
deleted file mode 100644
index abb9a2e10..000000000
--- a/cmd/helm/testdata/output/template-show-only-multiple.txt
+++ /dev/null
@@ -1,39 +0,0 @@
----
-# Source: subchart1/templates/service.yaml
-apiVersion: v1
-kind: Service
-metadata:
-  name: subchart1
-  labels:
-    helm.sh/chart: "subchart1-0.1.0"
-    app.kubernetes.io/instance: "RELEASE-NAME"
-    kube-version/major: "1"
-    kube-version/minor: "16"
-    kube-version/version: "v1.16.0"
-    kube-api-version/test: v1
-spec:
-  type: ClusterIP
-  ports:
-  - port: 80
-    targetPort: 80
-    protocol: TCP
-    name: nginx
-  selector:
-    app.kubernetes.io/name: subchart1
----
-# Source: subchart1/charts/subcharta/templates/service.yaml
-apiVersion: v1
-kind: Service
-metadata:
-  name: subcharta
-  labels:
-    helm.sh/chart: "subcharta-0.1.0"
-spec:
-  type: ClusterIP
-  ports:
-  - port: 80
-    targetPort: 80
-    protocol: TCP
-    name: apache
-  selector:
-    app.kubernetes.io/name: subcharta
diff --git a/cmd/helm/testdata/output/template-show-only-one.txt b/cmd/helm/testdata/output/template-show-only-one.txt
deleted file mode 100644
index f0dd0834e..000000000
--- a/cmd/helm/testdata/output/template-show-only-one.txt
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# Source: subchart1/templates/service.yaml
-apiVersion: v1
-kind: Service
-metadata:
-  name: subchart1
-  labels:
-    helm.sh/chart: "subchart1-0.1.0"
-    app.kubernetes.io/instance: "RELEASE-NAME"
-    kube-version/major: "1"
-    kube-version/minor: "16"
-    kube-version/version: "v1.16.0"
-    kube-api-version/test: v1
-spec:
-  type: ClusterIP
-  ports:
-  - port: 80
-    targetPort: 80
-    protocol: TCP
-    name: nginx
-  selector:
-    app.kubernetes.io/name: subchart1
diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go
index d93d616ee..3828771cc 100644
--- a/internal/resolver/resolver_test.go
+++ b/internal/resolver/resolver_test.go
@@ -216,61 +216,3 @@ func TestHashReq(t *testing.T) {
 		})
 	}
 }
-
-func TestGetLocalPath(t *testing.T) {
-	tests := []struct {
-		name      string
-		repo      string
-		chartpath string
-		expect    string
-		err       bool
-	}{
-		{
-			name:   "absolute path",
-			repo:   "file:////proc",
-			expect: "/proc",
-		},
-		{
-			name:      "relative path",
-			repo:      "file://../../../../cmd/helm/testdata/testcharts/signtest",
-			chartpath: "foo/bar",
-			expect:    "../../cmd/helm/testdata/testcharts/signtest",
-		},
-		{
-			name:      "current directory path",
-			repo:      "../charts/localdependency",
-			chartpath: "testdata/chartpath/charts",
-			expect:    "testdata/chartpath/charts/localdependency",
-		},
-		{
-			name:      "invalid local path",
-			repo:      "file://../testdata/notexist",
-			chartpath: "testdata/chartpath",
-			err:       true,
-		},
-		{
-			name:      "invalid path under current directory",
-			repo:      "../charts/nonexistentdependency",
-			chartpath: "testdata/chartpath/charts",
-			err:       true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			p, err := GetLocalPath(tt.repo, tt.chartpath)
-			if err != nil {
-				if tt.err {
-					return
-				}
-				t.Fatal(err)
-			}
-			if tt.err {
-				t.Fatalf("Expected error in test %q", tt.name)
-			}
-			if p != tt.expect {
-				t.Errorf("%q: expected %q, got %q", tt.name, tt.expect, p)
-			}
-		})
-	}
-}
diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go
index f25d115c4..e7bfeefc5 100644
--- a/pkg/action/upgrade_test.go
+++ b/pkg/action/upgrade_test.go
@@ -60,31 +60,6 @@ func TestUpgradeRelease_Wait(t *testing.T) {
 	is.Equal(res.Info.Status, release.StatusFailed)
 }
 
-func TestUpgradeRelease_CleanupOnFail(t *testing.T) {
-	is := assert.New(t)
-	req := require.New(t)
-
-	upAction := upgradeAction(t)
-	rel := releaseStub()
-	rel.Name = "come-fail-away"
-	rel.Info.Status = release.StatusDeployed
-	upAction.cfg.Releases.Create(rel)
-
-	failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
-	failer.WaitError = fmt.Errorf("I timed out")
-	failer.DeleteError = fmt.Errorf("I tried to delete nil")
-	upAction.cfg.KubeClient = failer
-	upAction.Wait = true
-	upAction.CleanupOnFail = true
-	vals := map[string]interface{}{}
-
-	res, err := upAction.Run(rel.Name, buildChart(), vals)
-	req.Error(err)
-	is.NotContains(err.Error(), "unable to cleanup resources")
-	is.Contains(res.Info.Description, "I timed out")
-	is.Equal(res.Info.Status, release.StatusFailed)
-}
-
 func TestUpgradeRelease_Atomic(t *testing.T) {
 	is := assert.New(t)
 	req := require.New(t)