diff --git a/Gopkg.lock b/Gopkg.lock index eddf22009..9eb933fef 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -337,6 +337,12 @@ revision = "d6bea18f789704b5f83375793155289da36a3c7f" version = "v0.0.1" +[[projects]] + name = "github.com/mattn/go-shellwords" + packages = ["."] + revision = "02e3cf038dcea8290e44424da473dd12be796a8a" + version = "v1.0.3" + [[projects]] name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] @@ -431,12 +437,14 @@ ".", "doc" ] - revision = "f62e98d28ab7ad31d707ba837a966378465c7b57" + revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4" + version = "v0.0.2" [[projects]] name = "github.com/spf13/pflag" packages = ["."] - revision = "9ff6c6923cfffbcd502984b8e0c80539a94968b7" + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" [[projects]] name = "github.com/stretchr/testify" @@ -1063,6 +1071,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "d27aa9378f7846f9dc4de8168f8a2dd6d9584fefddd26e2a9e172b9d8fc075c9" + inputs-digest = "82526354be9627a0e3796098ee9bed433a3e7958495f65e371ecc27d8c71c111" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/helm/delete_test.go b/cmd/helm/delete_test.go index 457b08d78..035b9d775 100644 --- a/cmd/helm/delete_test.go +++ b/cmd/helm/delete_test.go @@ -17,57 +17,51 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) func TestDelete(t *testing.T) { + resp := helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}) + rels := []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})} + tests := []releaseCase{ { - name: "basic delete", - args: []string{"aeneas"}, - flags: []string{}, - expected: "", // Output of a delete is an empty string and exit 0. - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + name: "basic delete", + cmd: "delete aeneas", + matches: `release "aeneas" deleted`, + resp: resp, + rels: rels, }, { - name: "delete with timeout", - args: []string{"aeneas"}, - flags: []string{"--timeout", "120"}, - expected: "", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + name: "delete with timeout", + cmd: "delete aeneas --timeout 120", + matches: `release "aeneas" deleted`, + resp: resp, + rels: rels, }, { - name: "delete without hooks", - args: []string{"aeneas"}, - flags: []string{"--no-hooks"}, - expected: "", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + name: "delete without hooks", + cmd: "delete aeneas --no-hooks", + matches: `release "aeneas" deleted`, + resp: resp, + rels: rels, }, { - name: "purge", - args: []string{"aeneas"}, - flags: []string{"--purge"}, - expected: "", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + name: "purge", + cmd: "delete aeneas --purge", + matches: `release "aeneas" deleted`, + resp: resp, + rels: rels, }, { - name: "delete without release", - args: []string{}, - err: true, + name: "delete without release", + cmd: "delete", + wantError: true, }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newDeleteCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/dependency_test.go b/cmd/helm/dependency_test.go index cc4519147..7d56e1d75 100644 --- a/cmd/helm/dependency_test.go +++ b/cmd/helm/dependency_test.go @@ -16,43 +16,35 @@ limitations under the License. package main import ( - "io" "testing" - - "github.com/spf13/cobra" - - "k8s.io/helm/pkg/helm" ) func TestDependencyListCmd(t *testing.T) { tests := []releaseCase{ { - name: "No such chart", - args: []string{"/no/such/chart"}, - err: true, + name: "No such chart", + cmd: "dependency list /no/such/chart", + wantError: true, }, { - name: "No requirements.yaml", - args: []string{"testdata/testcharts/alpine"}, - expected: "WARNING: no requirements at ", + name: "No requirements.yaml", + cmd: "dependency list testdata/testcharts/alpine", + matches: "WARNING: no requirements at ", }, { name: "Requirements in chart dir", - args: []string{"testdata/testcharts/reqtest"}, - expected: "NAME \tVERSION\tREPOSITORY \tSTATUS \n" + + cmd: "dependency list testdata/testcharts/reqtest", + matches: "NAME \tVERSION\tREPOSITORY \tSTATUS \n" + "reqsubchart \t0.1.0 \thttps://example.com/charts\tunpacked\n" + "reqsubchart2\t0.2.0 \thttps://example.com/charts\tunpacked\n" + "reqsubchart3\t>=0.1.0\thttps://example.com/charts\tok \n\n", }, { - name: "Requirements in chart archive", - args: []string{"testdata/testcharts/reqtest-0.1.0.tgz"}, - expected: "NAME \tVERSION\tREPOSITORY \tSTATUS \nreqsubchart \t0.1.0 \thttps://example.com/charts\tmissing\nreqsubchart2\t0.2.0 \thttps://example.com/charts\tmissing\n", + name: "Requirements in chart archive", + cmd: "dependency list testdata/testcharts/reqtest-0.1.0.tgz", + matches: "NAME \tVERSION\tREPOSITORY \tSTATUS \nreqsubchart \t0.1.0 \thttps://example.com/charts\tmissing\nreqsubchart2\t0.2.0 \thttps://example.com/charts\tmissing\n", }, } - - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newDependencyListCmd(out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/get.go b/cmd/helm/get.go index 3d2b32bc1..960a3c1bd 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -42,9 +42,10 @@ var errReleaseRequired = errors.New("release name is required") type getCmd struct { release string - out io.Writer - client helm.Interface version int + + out io.Writer + client helm.Interface } func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command { @@ -69,9 +70,9 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command { cmd.Flags().IntVar(&get.version, "revision", 0, "get the named release with revision") - cmd.AddCommand(newGetValuesCmd(nil, out)) - cmd.AddCommand(newGetManifestCmd(nil, out)) - cmd.AddCommand(newGetHooksCmd(nil, out)) + cmd.AddCommand(newGetValuesCmd(client, out)) + cmd.AddCommand(newGetManifestCmd(client, out)) + cmd.AddCommand(newGetHooksCmd(client, out)) return cmd } diff --git a/cmd/helm/get_hooks_test.go b/cmd/helm/get_hooks_test.go index 3a5dd2e75..c9d5bdb1b 100644 --- a/cmd/helm/get_hooks_test.go +++ b/cmd/helm/get_hooks_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -29,19 +26,17 @@ import ( func TestGetHooks(t *testing.T) { tests := []releaseCase{ { - name: "get hooks with release", - args: []string{"aeneas"}, - expected: helm.MockHookTemplate, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + name: "get hooks with release", + cmd: "get hooks aeneas", + matches: helm.MockHookTemplate, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, }, { - name: "get hooks without args", - args: []string{}, - err: true, + name: "get hooks without args", + cmd: "get hooks", + wantError: true, }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newGetHooksCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/get_manifest_test.go b/cmd/helm/get_manifest_test.go index df30914c7..c668826ca 100644 --- a/cmd/helm/get_manifest_test.go +++ b/cmd/helm/get_manifest_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -29,19 +26,17 @@ import ( func TestGetManifest(t *testing.T) { tests := []releaseCase{ { - name: "get manifest with release", - args: []string{"juno"}, - expected: helm.MockManifest, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"}), - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"})}, + name: "get manifest with release", + cmd: "get manifest juno", + matches: helm.MockManifest, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"}), + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "juno"})}, }, { - name: "get manifest without args", - args: []string{}, - err: true, + name: "get manifest without args", + cmd: "get manifest", + wantError: true, }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newGetManifestCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/get_test.go b/cmd/helm/get_test.go index 29f1500e6..f1b66992b 100644 --- a/cmd/helm/get_test.go +++ b/cmd/helm/get_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -29,20 +26,17 @@ import ( func TestGetCmd(t *testing.T) { tests := []releaseCase{ { - name: "get with a release", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), - args: []string{"thomas-guide"}, - expected: "REVISION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + helm.MockHookTemplate + "\nMANIFEST:", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})}, + name: "get with a release", + cmd: "get thomas-guide", + matches: "REVISION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + helm.MockHookTemplate + "\nMANIFEST:", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), }, { - name: "get requires release name arg", - err: true, + name: "get requires release name arg", + cmd: "get", + wantError: true, }, } - - cmd := func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newGetCmd(c, out) - } - runReleaseCases(t, tests, cmd) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/get_values_test.go b/cmd/helm/get_values_test.go index 024858738..63b637ba3 100644 --- a/cmd/helm/get_values_test.go +++ b/cmd/helm/get_values_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -29,19 +26,17 @@ import ( func TestGetValuesCmd(t *testing.T) { tests := []releaseCase{ { - name: "get values with a release", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), - args: []string{"thomas-guide"}, - expected: "name: \"value\"", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})}, + name: "get values with a release", + cmd: "get values thomas-guide", + matches: "name: \"value\"", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"})}, }, { - name: "get values requires release name arg", - err: true, + name: "get values requires release name arg", + cmd: "get values", + wantError: true, }, } - cmd := func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newGetValuesCmd(c, out) - } - runReleaseCases(t, tests, cmd) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 93abb645f..d9cf1d574 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -18,6 +18,7 @@ package main // import "k8s.io/helm/cmd/helm" import ( "fmt" + "io" "log" "os" "strings" @@ -61,7 +62,7 @@ Environment: $KUBECONFIG set an alternative Kubernetes configuration file (default "~/.kube/config") ` -func newRootCmd(args []string) *cobra.Command { +func newRootCmd(c helm.Interface, out io.Writer, args []string) *cobra.Command { cmd := &cobra.Command{ Use: "helm", Short: "The Helm package manager for Kubernetes.", @@ -72,8 +73,6 @@ func newRootCmd(args []string) *cobra.Command { settings.AddFlags(flags) - out := cmd.OutOrStdout() - cmd.AddCommand( // chart commands newCreateCmd(out), @@ -87,15 +86,15 @@ func newRootCmd(args []string) *cobra.Command { newVerifyCmd(out), // release commands - newDeleteCmd(nil, out), - newGetCmd(nil, out), - newHistoryCmd(nil, out), - newInstallCmd(nil, out), - newListCmd(nil, out), - newReleaseTestCmd(nil, out), - newRollbackCmd(nil, out), - newStatusCmd(nil, out), - newUpgradeCmd(nil, out), + newDeleteCmd(c, out), + newGetCmd(c, out), + newHistoryCmd(c, out), + newInstallCmd(c, out), + newListCmd(c, out), + newReleaseTestCmd(c, out), + newRollbackCmd(c, out), + newStatusCmd(c, out), + newUpgradeCmd(c, out), newCompletionCmd(out), newHomeCmd(out), @@ -131,7 +130,7 @@ func logf(format string, v ...interface{}) { } func main() { - cmd := newRootCmd(os.Args[1:]) + cmd := newRootCmd(nil, os.Stdout, os.Args[1:]) if err := cmd.Execute(); err != nil { os.Exit(1) } diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index baaa22bf6..098c9be26 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -19,7 +19,6 @@ package main import ( "bytes" "fmt" - "io" "io/ioutil" "os" "path/filepath" @@ -27,6 +26,7 @@ import ( "strings" "testing" + shellwords "github.com/mattn/go-shellwords" "github.com/spf13/cobra" "k8s.io/helm/pkg/hapi/release" @@ -35,42 +35,53 @@ import ( "k8s.io/helm/pkg/repo" ) -// releaseCmd is a command that works with a FakeClient -type releaseCmd func(c *helm.FakeClient, out io.Writer) *cobra.Command +func executeCommand(c helm.Interface, cmd string) (string, error) { + _, output, err := executeCommandC(c, cmd) + return output, err +} + +func executeCommandC(client helm.Interface, cmd string) (*cobra.Command, string, error) { + args, err := shellwords.Parse(cmd) + if err != nil { + return nil, "", err + } + buf := new(bytes.Buffer) + root := newRootCmd(client, buf, args) + root.SetOutput(buf) + root.SetArgs(args) + + c, err := root.ExecuteC() + + return c, buf.String(), err +} -// runReleaseCases runs a set of release cases through the given releaseCmd. -func runReleaseCases(t *testing.T, tests []releaseCase, rcmd releaseCmd) { - var buf bytes.Buffer +func testReleaseCmd(t *testing.T, tests []releaseCase) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &helm.FakeClient{ Rels: tt.rels, Responses: tt.responses, } - cmd := rcmd(c, &buf) - cmd.ParseFlags(tt.flags) - err := cmd.RunE(cmd, tt.args) - if (err != nil) != tt.err { + out, err := executeCommand(c, tt.cmd) + if (err != nil) != tt.wantError { t.Errorf("expected error, got '%v'", err) } - re := regexp.MustCompile(tt.expected) - if !re.Match(buf.Bytes()) { - t.Errorf("expected\n%q\ngot\n%q", tt.expected, buf.String()) + re := regexp.MustCompile(tt.matches) + if !re.MatchString(out) { + t.Errorf("expected\n%q\ngot\n%q", tt.matches, out) } - buf.Reset() }) } } // releaseCase describes a test case that works with releases. type releaseCase struct { - name string - args []string - flags []string - // expected is the string to be matched. This supports regular expressions. - expected string - err bool - resp *release.Release + name string + cmd string + // matches is the string to be matched. This supports regular expressions. + matches string + wantError bool + resp *release.Release // Rels are the available releases at the start of the test. rels []*release.Release responses map[string]release.TestRunStatus @@ -131,7 +142,7 @@ func ensureTestHome(home helmpath.Home, t *testing.T) error { } } - t.Logf("$HELM_HOME has been configured at %s.\n", settings.Home.String()) + t.Logf("$HELM_HOME has been configured at %s.\n", home) return nil } @@ -141,41 +152,39 @@ func TestRootCmd(t *testing.T) { defer cleanup() tests := []struct { - name string - args []string - envars map[string]string - home string + name, args, home string + envars map[string]string }{ { name: "defaults", - args: []string{"home"}, + args: "home", home: filepath.Join(os.Getenv("HOME"), "/.helm"), }, { name: "with --home set", - args: []string{"--home", "/foo"}, + args: "--home /foo", home: "/foo", }, { name: "subcommands with --home set", - args: []string{"home", "--home", "/foo"}, + args: "home --home /foo", home: "/foo", }, { name: "with $HELM_HOME set", - args: []string{"home"}, + args: "home", envars: map[string]string{"HELM_HOME": "/bar"}, home: "/bar", }, { name: "subcommands with $HELM_HOME set", - args: []string{"home"}, + args: "home", envars: map[string]string{"HELM_HOME": "/bar"}, home: "/bar", }, { name: "with $HELM_HOME and --home set", - args: []string{"home", "--home", "/foo"}, + args: "home --home /foo", envars: map[string]string{"HELM_HOME": "/bar"}, home: "/foo", }, @@ -192,12 +201,9 @@ func TestRootCmd(t *testing.T) { os.Setenv(k, v) } - cmd := newRootCmd(tt.args) - cmd.SetOutput(ioutil.Discard) - cmd.SetArgs(tt.args) - cmd.Run = func(*cobra.Command, []string) {} - if err := cmd.Execute(); err != nil { - t.Errorf("unexpected error: %s", err) + cmd, _, err := executeCommandC(nil, tt.args) + if err != nil { + t.Fatalf("unexpected error: %s", err) } if settings.Home.String() != tt.home { diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index b2026b476..282b08751 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - rpb "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -38,48 +35,42 @@ func TestHistoryCmd(t *testing.T) { tests := []releaseCase{ { name: "get history for release", - args: []string{"angry-bird"}, + cmd: "history angry-bird", rels: []*rpb.Release{ mk("angry-bird", 4, rpb.Status_DEPLOYED), mk("angry-bird", 3, rpb.Status_SUPERSEDED), mk("angry-bird", 2, rpb.Status_SUPERSEDED), mk("angry-bird", 1, rpb.Status_SUPERSEDED), }, - expected: `REVISION\s+UPDATED\s+STATUS\s+CHART\s+DESCRIPTION \n1\s+(.*)\s+SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n2(.*)SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n3(.*)SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n4(.*)DEPLOYED\s+foo-0.1.0-beta.1\s+Release mock\n`, + matches: `REVISION\s+UPDATED\s+STATUS\s+CHART\s+DESCRIPTION \n1\s+(.*)\s+SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n2(.*)SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n3(.*)SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n4(.*)DEPLOYED\s+foo-0.1.0-beta.1\s+Release mock\n`, }, { - name: "get history with max limit set", - args: []string{"angry-bird"}, - flags: []string{"--max", "2"}, + name: "get history with max limit set", + cmd: "history angry-bird --max 2", rels: []*rpb.Release{ mk("angry-bird", 4, rpb.Status_DEPLOYED), mk("angry-bird", 3, rpb.Status_SUPERSEDED), }, - expected: `REVISION\s+UPDATED\s+STATUS\s+CHART\s+DESCRIPTION \n3\s+(.*)\s+SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n4\s+(.*)\s+DEPLOYED\s+foo-0.1.0-beta.1\s+Release mock\n`, + matches: `REVISION\s+UPDATED\s+STATUS\s+CHART\s+DESCRIPTION \n3\s+(.*)\s+SUPERSEDED\s+foo-0.1.0-beta.1\s+Release mock\n4\s+(.*)\s+DEPLOYED\s+foo-0.1.0-beta.1\s+Release mock\n`, }, { - name: "get history with yaml output format", - args: []string{"angry-bird"}, - flags: []string{"--output", "yaml"}, + name: "get history with yaml output format", + cmd: "history angry-bird --output yaml", rels: []*rpb.Release{ mk("angry-bird", 4, rpb.Status_DEPLOYED), mk("angry-bird", 3, rpb.Status_SUPERSEDED), }, - expected: "- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 3\n status: SUPERSEDED\n updated: (.*)\n- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 4\n status: DEPLOYED\n updated: (.*)\n\n", + matches: "- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 3\n status: SUPERSEDED\n updated: (.*)\n- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 4\n status: DEPLOYED\n updated: (.*)\n\n", }, { - name: "get history with json output format", - args: []string{"angry-bird"}, - flags: []string{"--output", "json"}, + name: "get history with json output format", + cmd: "history angry-bird --output json", rels: []*rpb.Release{ mk("angry-bird", 4, rpb.Status_DEPLOYED), mk("angry-bird", 3, rpb.Status_SUPERSEDED), }, - expected: `[{"revision":3,"updated":".*","status":"SUPERSEDED","chart":"foo\-0.1.0-beta.1","description":"Release mock"},{"revision":4,"updated":".*","status":"DEPLOYED","chart":"foo\-0.1.0-beta.1","description":"Release mock"}]\n`, + matches: `[{"revision":3,"updated":".*","status":"SUPERSEDED","chart":"foo\-0.1.0-beta.1","description":"Release mock"},{"revision":4,"updated":".*","status":"DEPLOYED","chart":"foo\-0.1.0-beta.1","description":"Release mock"}]\n`, }, } - - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newHistoryCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/install.go b/cmd/helm/install.go index cf11da45e..fb33ca65c 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -105,31 +105,31 @@ charts in a repository, use 'helm search'. ` type installCmd struct { - name string - valueFiles valueFiles - chartPath string - dryRun bool - disableHooks bool - replace bool - verify bool - keyring string - out io.Writer - client helm.Interface - values []string - stringValues []string - nameTemplate string - version string - timeout int64 - wait bool - repoURL string - username string - password string - devel bool - depUp bool - - certFile string - keyFile string - caFile string + name string // --name + valueFiles valueFiles // --values + dryRun bool // --dry-run + disableHooks bool // --disable-hooks + replace bool // --replace + verify bool // --verify + keyring string // --keyring + values []string // --set + stringValues []string // --set-string + nameTemplate string // --name-template + version string // --version + timeout int64 // --timeout + wait bool // --wait + repoURL string // --repo + username string // --username + password string // --password + devel bool // --devel + depUp bool // --dep-up + certFile string // --cert-file + keyFile string // --key-file + caFile string // --ca-file + chartPath string // arg + + out io.Writer + client helm.Interface } type valueFiles []string @@ -291,7 +291,7 @@ func (i *installCmd) run() error { } // Merges source and destination map, preferring values from the source map -func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} { +func mergeValues(dest, src map[string]interface{}) map[string]interface{} { for k, v := range src { // If the key doesn't exist already, then just set the key to that value if _, exists := dest[k]; !exists { diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 8a0aed552..a384c299a 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -17,14 +17,10 @@ limitations under the License. package main import ( - "io" "reflect" "regexp" - "strings" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/helm" ) @@ -32,125 +28,110 @@ func TestInstall(t *testing.T) { tests := []releaseCase{ // Install, base case { - name: "basic install", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name aeneas", " "), - expected: "aeneas", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + name: "basic install", + cmd: "install testdata/testcharts/alpine --name aeneas", + matches: "aeneas", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), }, // Install, no hooks { - name: "install without hooks", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name aeneas --no-hooks", " "), - expected: "aeneas", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + name: "install without hooks", + cmd: "install testdata/testcharts/alpine --name aeneas --no-hooks", + matches: "aeneas", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), }, // Install, values from cli { - name: "install with values", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name virgil --set foo=bar", " "), - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), - expected: "virgil", + name: "install with values", + cmd: "install testdata/testcharts/alpine --name virgil --set foo=bar", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + matches: "virgil", }, // Install, values from cli via multiple --set { - name: "install with multiple values", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name virgil --set foo=bar --set bar=foo", " "), - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), - expected: "virgil", + name: "install with multiple values", + cmd: "install testdata/testcharts/alpine --name virgil --set foo=bar --set bar=foo", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + matches: "virgil", }, // Install, values from yaml { - name: "install with values", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml", " "), - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), - expected: "virgil", + name: "install with values", + cmd: "install testdata/testcharts/alpine --name virgil -f testdata/testcharts/alpine/extra_values.yaml", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + matches: "virgil", }, // Install, values from multiple yaml { - name: "install with values", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name virgil -f testdata/testcharts/alpine/extra_values.yaml -f testdata/testcharts/alpine/more_values.yaml", " "), - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), - expected: "virgil", + name: "install with values", + cmd: "install testdata/testcharts/alpine --name virgil -f testdata/testcharts/alpine/extra_values.yaml -f testdata/testcharts/alpine/more_values.yaml", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + matches: "virgil", }, // Install, no charts { - name: "install with no chart specified", - args: []string{}, - err: true, + name: "install with no chart specified", + cmd: "install", + wantError: true, }, // Install, re-use name { - name: "install and replace release", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name aeneas --replace", " "), - expected: "aeneas", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + name: "install and replace release", + cmd: "install testdata/testcharts/alpine --name aeneas --replace", + matches: "aeneas", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), }, // Install, with timeout { - name: "install with a timeout", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name foobar --timeout 120", " "), - expected: "foobar", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "foobar"}), + name: "install with a timeout", + cmd: "install testdata/testcharts/alpine --name foobar --timeout 120", + matches: "foobar", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "foobar"}), }, // Install, with wait { - name: "install with a wait", - args: []string{"testdata/testcharts/alpine"}, - flags: strings.Split("--name apollo --wait", " "), - expected: "apollo", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}), + name: "install with a wait", + cmd: "install testdata/testcharts/alpine --name apollo --wait", + matches: "apollo", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "apollo"}), }, // Install, using the name-template { - name: "install with name-template", - args: []string{"testdata/testcharts/alpine"}, - flags: []string{"--name-template", "{{upper \"foobar\"}}"}, - expected: "FOOBAR", - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "FOOBAR"}), + name: "install with name-template", + cmd: "install testdata/testcharts/alpine --name-template '{{upper \"foobar\"}}'", + matches: "FOOBAR", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "FOOBAR"}), }, // Install, perform chart verification along the way. { - name: "install with verification, missing provenance", - args: []string{"testdata/testcharts/compressedchart-0.1.0.tgz"}, - flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "), - err: true, + name: "install with verification, missing provenance", + cmd: "install testdata/testcharts/compressedchart-0.1.0.tgz --verify --keyring testdata/helm-test-key.pub", + wantError: true, }, { - name: "install with verification, directory instead of file", - args: []string{"testdata/testcharts/signtest"}, - flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "), - err: true, + name: "install with verification, directory instead of file", + cmd: "install testdata/testcharts/signtest --verify --keyring testdata/helm-test-key.pub", + wantError: true, }, { - name: "install with verification, valid", - args: []string{"testdata/testcharts/signtest-0.1.0.tgz"}, - flags: strings.Split("--verify --keyring testdata/helm-test-key.pub", " "), + name: "install with verification, valid", + cmd: "install testdata/testcharts/signtest-0.1.0.tgz --verify --keyring testdata/helm-test-key.pub", }, // Install, chart with missing dependencies in /charts { - name: "install chart with missing dependencies", - args: []string{"testdata/testcharts/chart-missing-deps"}, - err: true, + name: "install chart with missing dependencies", + cmd: "install testdata/testcharts/chart-missing-deps", + wantError: true, }, // Install, chart with bad requirements.yaml in /charts { - name: "install chart with bad requirements.yaml", - args: []string{"testdata/testcharts/chart-bad-requirements"}, - err: true, + name: "install chart with bad requirements.yaml", + cmd: "install testdata/testcharts/chart-bad-requirements", + wantError: true, }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newInstallCmd(c, out) - }) + testReleaseCmd(t, tests) } type nameTemplateTestCase struct { diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index 3d5051278..1634e183d 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -17,11 +17,8 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) @@ -30,99 +27,100 @@ func TestListCmd(t *testing.T) { tests := []releaseCase{ { name: "with a release", + cmd: "list", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), }, - expected: "thomas-guide", + matches: "thomas-guide", }, { name: "list", + cmd: "list", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas"}), }, - expected: `NAME\s+REVISION\s+UPDATED\s+STATUS\s+CHART\s+NAMESPACE\natlas\s+1\s+(.*)\s+DEPLOYED\s+foo-0.1.0-beta.1\s+default`, + matches: `NAME\s+REVISION\s+UPDATED\s+STATUS\s+CHART\s+NAMESPACE\natlas\s+1\s+(.*)\s+DEPLOYED\s+foo-0.1.0-beta.1\s+default`, }, { - name: "list, one deployed, one failed", - flags: []string{"-q"}, + name: "list, one deployed, one failed", + cmd: "list -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_FAILED}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, - expected: "thomas-guide\natlas-guide", + matches: "thomas-guide\natlas-guide", }, { - name: "with a release, multiple flags", - flags: []string{"--deleted", "--deployed", "--failed", "-q"}, + name: "with a release, multiple flags", + cmd: "list --deleted --deployed --failed -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETED}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, // Note: We're really only testing that the flags parsed correctly. Which results are returned // depends on the backend. And until pkg/helm is done, we can't mock this. - expected: "thomas-guide\natlas-guide", + matches: "thomas-guide\natlas-guide", }, { - name: "with a release, multiple flags", - flags: []string{"--all", "-q"}, + name: "with a release, multiple flags", + cmd: "list --all -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETED}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, // See note on previous test. - expected: "thomas-guide\natlas-guide", + matches: "thomas-guide\natlas-guide", }, { - name: "with a release, multiple flags, deleting", - flags: []string{"--all", "-q"}, + name: "with a release, multiple flags, deleting", + cmd: "list --all -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_DELETING}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, // See note on previous test. - expected: "thomas-guide\natlas-guide", + matches: "thomas-guide\natlas-guide", }, { - name: "namespace defined, multiple flags", - flags: []string{"--all", "-q", "--namespace test123"}, + name: "namespace defined, multiple flags", + cmd: "list --all -q --namespace test123", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", Namespace: "test123"}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", Namespace: "test321"}), }, // See note on previous test. - expected: "thomas-guide", + matches: "thomas-guide", }, { - name: "with a pending release, multiple flags", - flags: []string{"--all", "-q"}, + name: "with a pending release, multiple flags", + cmd: "list --all -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_PENDING_INSTALL}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, - expected: "thomas-guide\natlas-guide", + matches: "thomas-guide\natlas-guide", }, { - name: "with a pending release, pending flag", - flags: []string{"--pending", "-q"}, + name: "with a pending release, pending flag", + cmd: "list --pending -q", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_PENDING_INSTALL}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "wild-idea", StatusCode: release.Status_PENDING_UPGRADE}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-maps", StatusCode: release.Status_PENDING_ROLLBACK}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "atlas-guide", StatusCode: release.Status_DEPLOYED}), }, - expected: "thomas-guide\nwild-idea\ncrazy-maps", + matches: "thomas-guide\nwild-idea\ncrazy-maps", }, { name: "with old releases", + cmd: "list", rels: []*release.Release{ helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide"}), helm.ReleaseMock(&helm.MockReleaseOptions{Name: "thomas-guide", StatusCode: release.Status_FAILED}), }, - expected: "thomas-guide", + matches: "thomas-guide", }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newListCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/release_testing_test.go b/cmd/helm/release_testing_test.go index 6b36c4ee0..df12556ca 100644 --- a/cmd/helm/release_testing_test.go +++ b/cmd/helm/release_testing_test.go @@ -17,56 +17,46 @@ limitations under the License. package main import ( - "io" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" - "k8s.io/helm/pkg/helm" ) func TestReleaseTesting(t *testing.T) { tests := []releaseCase{ { name: "basic test", - args: []string{"example-release"}, - flags: []string{}, + cmd: "test example-release", responses: map[string]release.TestRunStatus{"PASSED: green lights everywhere": release.TestRun_SUCCESS}, - err: false, + wantError: false, }, { name: "test failure", - args: []string{"example-fail"}, - flags: []string{}, + cmd: "test example-fail", responses: map[string]release.TestRunStatus{"FAILURE: red lights everywhere": release.TestRun_FAILURE}, - err: true, + wantError: true, }, { name: "test unknown", - args: []string{"example-unknown"}, - flags: []string{}, + cmd: "test example-unknown", responses: map[string]release.TestRunStatus{"UNKNOWN: yellow lights everywhere": release.TestRun_UNKNOWN}, - err: false, + wantError: false, }, { name: "test error", - args: []string{"example-error"}, - flags: []string{}, + cmd: "test example-error", responses: map[string]release.TestRunStatus{"ERROR: yellow lights everywhere": release.TestRun_FAILURE}, - err: true, + wantError: true, }, { name: "test running", - args: []string{"example-running"}, - flags: []string{}, + cmd: "test example-running", responses: map[string]release.TestRunStatus{"RUNNING: things are happpeningggg": release.TestRun_RUNNING}, - err: false, + wantError: false, }, { - name: "multiple tests example", - args: []string{"example-suite"}, - flags: []string{}, + name: "multiple tests example", + cmd: "test example-suite", responses: map[string]release.TestRunStatus{ "RUNNING: things are happpeningggg": release.TestRun_RUNNING, "PASSED: party time": release.TestRun_SUCCESS, @@ -74,11 +64,8 @@ func TestReleaseTesting(t *testing.T) { "FAILURE: good thing u checked :)": release.TestRun_FAILURE, "RUNNING: things are happpeningggg yet again": release.TestRun_RUNNING, "PASSED: feel free to party again": release.TestRun_SUCCESS}, - err: true, + wantError: true, }, } - - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newReleaseTestCmd(c, out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index 157b1cc5b..f72745cb7 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -17,13 +17,10 @@ limitations under the License. package main import ( - "io" + "fmt" "os" "testing" - "github.com/spf13/cobra" - - "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo/repotest" ) @@ -48,17 +45,13 @@ func TestRepoAddCmd(t *testing.T) { settings.Home = thome - tests := []releaseCase{ - { - name: "add a repository", - args: []string{testName, srv.URL()}, - expected: "\"" + testName + "\" has been added to your repositories", - }, - } + tests := []releaseCase{{ + name: "add a repository", + cmd: fmt.Sprintf("repo add %s %s --home %s", testName, srv.URL(), thome), + matches: "\"" + testName + "\" has been added to your repositories", + }} - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newRepoAddCmd(out) - }) + testReleaseCmd(t, tests) } func TestRepoAdd(t *testing.T) { diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index f1479b2eb..3b0839312 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -17,45 +17,32 @@ limitations under the License. package main import ( - "io" "testing" - - "github.com/spf13/cobra" - - "k8s.io/helm/pkg/helm" ) func TestRollbackCmd(t *testing.T) { tests := []releaseCase{ { - name: "rollback a release", - args: []string{"funny-honey", "1"}, - expected: "Rollback was a success! Happy Helming!", + name: "rollback a release", + cmd: "rollback funny-honey 1", + matches: "Rollback was a success! Happy Helming!", }, { - name: "rollback a release with timeout", - args: []string{"funny-honey", "1"}, - flags: []string{"--timeout", "120"}, - expected: "Rollback was a success! Happy Helming!", + name: "rollback a release with timeout", + cmd: "rollback funny-honey 1 --timeout 120", + matches: "Rollback was a success! Happy Helming!", }, { - name: "rollback a release with wait", - args: []string{"funny-honey", "1"}, - flags: []string{"--wait"}, - expected: "Rollback was a success! Happy Helming!", + name: "rollback a release with wait", + cmd: "rollback funny-honey 1 --wait", + matches: "Rollback was a success! Happy Helming!", }, { - name: "rollback a release without revision", - args: []string{"funny-honey"}, - err: true, + name: "rollback a release without revision", + cmd: "rollback funny-honey", + wantError: true, }, } - - cmd := func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newRollbackCmd(c, out) - } - - runReleaseCases(t, tests, cmd) - + testReleaseCmd(t, tests) } diff --git a/cmd/helm/search/search_test.go b/cmd/helm/search/search_test.go index 754c5ac6a..19568d9ca 100644 --- a/cmd/helm/search/search_test.go +++ b/cmd/helm/search/search_test.go @@ -236,36 +236,38 @@ func TestSearchByName(t *testing.T) { i := loadTestIndex(t, false) for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { - charts, err := i.Search(tt.query, 100, tt.regexp) - if err != nil { - if tt.fail { - if !strings.Contains(err.Error(), tt.failMsg) { - t.Fatalf("%s: Unexpected error message: %s", tt.name, err) + charts, err := i.Search(tt.query, 100, tt.regexp) + if err != nil { + if tt.fail { + if !strings.Contains(err.Error(), tt.failMsg) { + t.Fatalf("Unexpected error message: %s", err) + } + return } - continue + t.Fatalf("%s: %s", tt.name, err) } - t.Fatalf("%s: %s", tt.name, err) - } - // Give us predictably ordered results. - SortScore(charts) + // Give us predictably ordered results. + SortScore(charts) - l := len(charts) - if l != len(tt.expect) { - t.Fatalf("%s: Expected %d result, got %d", tt.name, len(tt.expect), l) - } - // For empty result sets, just keep going. - if l == 0 { - continue - } + l := len(charts) + if l != len(tt.expect) { + t.Fatalf("Expected %d result, got %d", len(tt.expect), l) + } + // For empty result sets, just keep going. + if l == 0 { + return + } - for i, got := range charts { - ex := tt.expect[i] - if got.Name != ex.Name { - t.Errorf("%s[%d]: Expected name %q, got %q", tt.name, i, ex.Name, got.Name) + for i, got := range charts { + ex := tt.expect[i] + if got.Name != ex.Name { + t.Errorf("[%d]: Expected name %q, got %q", i, ex.Name, got.Name) + } } - } + }) } } diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 734f752f5..6541046b9 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -17,72 +17,60 @@ limitations under the License. package main import ( - "io" "testing" - - "github.com/spf13/cobra" - - "k8s.io/helm/pkg/helm" ) func TestSearchCmd(t *testing.T) { tests := []releaseCase{ { - name: "search for 'maria', expect one match", - args: []string{"maria"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/mariadb\t0.3.0 \t \tChart for MariaDB", + name: "search for 'maria', expect one match", + cmd: "search maria", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/mariadb\t0.3.0 \t \tChart for MariaDB", }, { - name: "search for 'alpine', expect two matches", - args: []string{"alpine"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine', expect two matches", + cmd: "search alpine", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alpine' with versions, expect three matches", - args: []string{"alpine"}, - flags: []string{"--versions"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine' with versions, expect three matches", + cmd: "search alpine --versions", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alpine' with version constraint, expect one match with version 0.1.0", - args: []string{"alpine"}, - flags: []string{"--version", ">= 0.1, < 0.2"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine' with version constraint, expect one match with version 0.1.0", + cmd: "search alpine --version '>= 0.1, < 0.2'", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alpine' with version constraint, expect one match with version 0.1.0", - args: []string{"alpine"}, - flags: []string{"--versions", "--version", ">= 0.1, < 0.2"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine' with version constraint, expect one match with version 0.1.0", + cmd: "search alpine --versions --version '>= 0.1, < 0.2'", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alpine' with version constraint, expect one match with version 0.2.0", - args: []string{"alpine"}, - flags: []string{"--version", ">= 0.1"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine' with version constraint, expect one match with version 0.2.0", + cmd: "search alpine --version '>= 0.1'", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alpine' with version constraint and --versions, expect two matches", - args: []string{"alpine"}, - flags: []string{"--versions", "--version", ">= 0.1"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", + name: "search for 'alpine' with version constraint and --versions, expect two matches", + cmd: "search alpine --versions --version '>= 0.1'", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod\ntesting/alpine\t0.1.0 \t1.2.3 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'syzygy', expect no matches", - args: []string{"syzygy"}, - expected: "No results found", + name: "search for 'syzygy', expect no matches", + cmd: "search syzygy", + matches: "No results found", }, { - name: "search for 'alp[a-z]+', expect two matches", - args: []string{"alp[a-z]+"}, - flags: []string{"--regexp"}, - expected: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", + name: "search for 'alp[a-z]+', expect two matches", + cmd: "search alp[a-z]+ --regexp", + matches: "NAME \tCHART VERSION\tAPP VERSION\tDESCRIPTION \ntesting/alpine\t0.2.0 \t2.3.4 \tDeploy a basic Alpine Linux pod", }, { - name: "search for 'alp[', expect failure to compile regexp", - args: []string{"alp["}, - flags: []string{"--regexp"}, - err: true, + name: "search for 'alp[', expect failure to compile regexp", + cmd: "search alp[ --regexp", + wantError: true, }, } @@ -90,8 +78,5 @@ func TestSearchCmd(t *testing.T) { defer cleanup() settings.Home = "testdata/helmhome" - - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newSearchCmd(out) - }) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index d503c8626..991136857 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -18,22 +18,18 @@ package main import ( "fmt" - "io" "testing" "time" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/hapi/release" - "k8s.io/helm/pkg/helm" ) func TestStatusCmd(t *testing.T) { tests := []releaseCase{ { - name: "get status of a deployed release", - args: []string{"flummoxed-chickadee"}, - expected: outputWithStatus("DEPLOYED"), + name: "get status of a deployed release", + cmd: "status flummoxed-chickadee", + matches: outputWithStatus("DEPLOYED"), rels: []*release.Release{ releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, @@ -41,9 +37,9 @@ func TestStatusCmd(t *testing.T) { }, }, { - name: "get status of a deployed release with notes", - args: []string{"flummoxed-chickadee"}, - expected: outputWithStatus("DEPLOYED\n\nNOTES:\nrelease notes\n"), + name: "get status of a deployed release with notes", + cmd: "status flummoxed-chickadee", + matches: outputWithStatus("DEPLOYED\n\nNOTES:\nrelease notes\n"), rels: []*release.Release{ releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, @@ -52,10 +48,9 @@ func TestStatusCmd(t *testing.T) { }, }, { - name: "get status of a deployed release with notes in json", - args: []string{"flummoxed-chickadee"}, - flags: []string{"-o", "json"}, - expected: `{"name":"flummoxed-chickadee","info":{"status":{"code":1,"notes":"release notes"},"first_deployed":(.*),"last_deployed":(.*)}}`, + name: "get status of a deployed release with notes in json", + cmd: "status flummoxed-chickadee -o json", + matches: `{"name":"flummoxed-chickadee","info":{"status":{"code":1,"notes":"release notes"},"first_deployed":(.*),"last_deployed":(.*)}}`, rels: []*release.Release{ releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, @@ -64,9 +59,9 @@ func TestStatusCmd(t *testing.T) { }, }, { - name: "get status of a deployed release with resources", - args: []string{"flummoxed-chickadee"}, - expected: outputWithStatus("DEPLOYED\n\nRESOURCES:\nresource A\nresource B\n\n"), + name: "get status of a deployed release with resources", + cmd: "status flummoxed-chickadee", + matches: outputWithStatus("DEPLOYED\n\nRESOURCES:\nresource A\nresource B\n\n"), rels: []*release.Release{ releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, @@ -75,10 +70,9 @@ func TestStatusCmd(t *testing.T) { }, }, { - name: "get status of a deployed release with resources in YAML", - args: []string{"flummoxed-chickadee"}, - flags: []string{"-o", "yaml"}, - expected: "info:\n (.*)first_deployed:\n (.*)seconds: 242085845\n (.*)last_deployed:\n (.*)seconds: 242085845\n (.*)status:\n code: 1\n (.*)resources: |\n (.*)resource A\n (.*)resource B\nname: flummoxed-chickadee\n", + name: "get status of a deployed release with resources in YAML", + cmd: "status flummoxed-chickadee -o yaml", + matches: "info:\n (.*)first_deployed:\n (.*)seconds: 242085845\n (.*)last_deployed:\n (.*)seconds: 242085845\n (.*)status:\n code: 1\n (.*)resources: |\n (.*)resource A\n (.*)resource B\nname: flummoxed-chickadee\n", rels: []*release.Release{ releaseMockWithStatus(&release.Status{ Code: release.Status_DEPLOYED, @@ -88,8 +82,8 @@ func TestStatusCmd(t *testing.T) { }, { name: "get status of a deployed release with test suite", - args: []string{"flummoxed-chickadee"}, - expected: outputWithStatus( + cmd: "status flummoxed-chickadee", + matches: outputWithStatus( "DEPLOYED\n\nTEST SUITE:\nLast Started: (.*)\nLast Completed: (.*)\n\n" + "TEST \tSTATUS (.*)\tINFO (.*)\tSTARTED (.*)\tCOMPLETED (.*)\n" + "test run 1\tSUCCESS (.*)\textra info\t(.*)\t(.*)\n" + @@ -120,11 +114,7 @@ func TestStatusCmd(t *testing.T) { }, }, } - - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newStatusCmd(c, out) - }) - + testReleaseCmd(t, tests) } func outputWithStatus(status string) string { diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 9576d3512..eb5d7b011 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -17,14 +17,11 @@ limitations under the License. package main import ( - "io" "io/ioutil" "os" "path/filepath" "testing" - "github.com/spf13/cobra" - "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/hapi/chart" "k8s.io/helm/pkg/hapi/release" @@ -91,80 +88,73 @@ func TestUpgradeCmd(t *testing.T) { t.Errorf("Error loading chart with missing dependencies: %v", err) } + relMock := func(n string, v int, ch *chart.Chart) *release.Release { + return helm.ReleaseMock(&helm.MockReleaseOptions{Name: n, Version: v, Chart: ch}) + } + tests := []releaseCase{ { - name: "upgrade a release", - args: []string{"funny-bunny", chartPath}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 2, Chart: ch}), - expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 2, Chart: ch})}, + name: "upgrade a release", + cmd: "upgrade funny-bunny " + chartPath, + resp: relMock("funny-bunny", 2, ch), + matches: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("funny-bunny", 2, ch)}, }, { - name: "upgrade a release with timeout", - args: []string{"funny-bunny", chartPath}, - flags: []string{"--timeout", "120"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 3, Chart: ch2}), - expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 3, Chart: ch2})}, + name: "upgrade a release with timeout", + cmd: "upgrade funny-bunny --timeout 120 " + chartPath, + resp: relMock("funny-bunny", 3, ch2), + matches: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("funny-bunny", 3, ch2)}, }, { - name: "upgrade a release with --reset-values", - args: []string{"funny-bunny", chartPath}, - flags: []string{"--reset-values", "true"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 4, Chart: ch2}), - expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 4, Chart: ch2})}, + name: "upgrade a release with --reset-values", + cmd: "upgrade funny-bunny --reset-values " + chartPath, + resp: relMock("funny-bunny", 4, ch2), + matches: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("funny-bunny", 4, ch2)}, }, { - name: "upgrade a release with --reuse-values", - args: []string{"funny-bunny", chartPath}, - flags: []string{"--reuse-values", "true"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 5, Chart: ch2}), - expected: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "funny-bunny", Version: 5, Chart: ch2})}, + name: "upgrade a release with --reuse-values", + cmd: "upgrade funny-bunny --reuse-values " + chartPath, + resp: relMock("funny-bunny", 5, ch2), + matches: "Release \"funny-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("funny-bunny", 5, ch2)}, }, { - name: "install a release with 'upgrade --install'", - args: []string{"zany-bunny", chartPath}, - flags: []string{"-i"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "zany-bunny", Version: 1, Chart: ch}), - expected: "Release \"zany-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "zany-bunny", Version: 1, Chart: ch})}, + name: "install a release with 'upgrade --install'", + cmd: "upgrade zany-bunny -i " + chartPath, + resp: relMock("zany-bunny", 1, ch), + matches: "Release \"zany-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("zany-bunny", 1, ch)}, }, { - name: "install a release with 'upgrade --install' and timeout", - args: []string{"crazy-bunny", chartPath}, - flags: []string{"-i", "--timeout", "120"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch}), - expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch})}, + name: "install a release with 'upgrade --install' and timeout", + cmd: "upgrade crazy-bunny -i --timeout 120 " + chartPath, + resp: relMock("crazy-bunny", 1, ch), + matches: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("crazy-bunny", 1, ch)}, }, { - name: "upgrade a release with wait", - args: []string{"crazy-bunny", chartPath}, - flags: []string{"--wait"}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2}), - expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", - rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2})}, + name: "upgrade a release with wait", + cmd: "upgrade crazy-bunny --wait " + chartPath, + resp: relMock("crazy-bunny", 2, ch2), + matches: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{relMock("crazy-bunny", 2, ch2)}, }, { - name: "upgrade a release with missing dependencies", - args: []string{"bonkers-bunny", missingDepsPath}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "bonkers-bunny", Version: 1, Chart: ch3}), - err: true, + name: "upgrade a release with missing dependencies", + cmd: "upgrade bonkers-bunny" + missingDepsPath, + resp: relMock("bonkers-bunny", 1, ch3), + wantError: true, }, { - name: "upgrade a release with bad dependencies", - args: []string{"bonkers-bunny", badDepsPath}, - resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "bonkers-bunny", Version: 1, Chart: ch3}), - err: true, + name: "upgrade a release with bad dependencies", + cmd: "upgrade bonkers-bunny " + badDepsPath, + resp: relMock("bonkers-bunny", 1, ch3), + wantError: true, }, } - - cmd := func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newUpgradeCmd(c, out) - } - - runReleaseCases(t, tests, cmd) + testReleaseCmd(t, tests) } diff --git a/cmd/helm/version_test.go b/cmd/helm/version_test.go index 6aa8689b1..9da1a9753 100644 --- a/cmd/helm/version_test.go +++ b/cmd/helm/version_test.go @@ -17,13 +17,9 @@ package main import ( "fmt" - "io" "regexp" "testing" - "github.com/spf13/cobra" - - "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/version" ) @@ -33,18 +29,15 @@ func TestVersion(t *testing.T) { tests := []releaseCase{ { - name: "default", - args: []string{}, - expected: clientVersion, + name: "default", + cmd: "version", + matches: clientVersion, }, { - name: "template", - args: []string{}, - flags: []string{"--template", "{{ .Client.SemVer }}"}, - expected: lver, + name: "template", + cmd: "version --template='{{.Client.SemVer}}'", + matches: lver, }, } - runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { - return newVersionCmd(out) - }) + testReleaseCmd(t, tests) }