diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 779403d8a..4552df3fc 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -90,7 +90,11 @@ func newRootCmd() *cobra.Command { var RootCommand = newRootCmd() func main() { + out := os.Stdout + client := helm.NewClient(helm.HelmHost(helm.Config.ServAddr)) + cmd := RootCommand + cmd.AddCommand(newListCmd(client, out)) if err := cmd.Execute(); err != nil { os.Exit(1) } diff --git a/cmd/helm/list.go b/cmd/helm/list.go index fc62677cf..a767cbec9 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -19,7 +19,6 @@ package main import ( "fmt" "io" - "os" "strings" "github.com/gosuri/uitable" @@ -55,17 +54,20 @@ flag with the '--offset' flag allows you to page through results. ` type lister struct { + filter string long bool - max int + limit int offset string byDate bool sortDesc bool out io.Writer + client helm.Interface } -func newListCmd(out io.Writer) *cobra.Command { +func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { list := &lister{ - out: out, + client: client, + out: out, } cmd := &cobra.Command{ Use: "list [flags] [FILTER]", @@ -74,28 +76,22 @@ func newListCmd(out io.Writer) *cobra.Command { Aliases: []string{"ls"}, PersistentPreRunE: setupConnection, RunE: func(cmd *cobra.Command, args []string) error { - return list.run(args) + if len(args) > 0 { + list.filter = strings.Join(args, " ") + } + return list.run() }, } f := cmd.Flags() f.BoolVarP(&list.long, "long", "l", false, "output long listing format") f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date") f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order") - f.IntVarP(&list.max, "max", "m", 256, "maximum number of releases to fetch") + f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch") f.StringVarP(&list.offset, "offset", "o", "", "the next release name in the list, used to offset from start value") return cmd } -func init() { - RootCommand.AddCommand(newListCmd(os.Stdout)) -} - -func (l *lister) run(args []string) error { - var filter string - if len(args) > 0 { - filter = strings.Join(args, " ") - } - +func (l *lister) run() error { sortBy := services.ListSort_NAME if l.byDate { sortBy = services.ListSort_LAST_RELEASED @@ -106,7 +102,14 @@ func (l *lister) run(args []string) error { sortOrder = services.ListSort_DESC } - res, err := helm.ListReleases(l.max, l.offset, sortBy, sortOrder, filter) + res, err := l.client.ListReleases( + helm.ReleaseListLimit(l.limit), + helm.ReleaseListOffset(l.offset), + helm.ReleaseListFilter(l.filter), + helm.ReleaseListSort(int32(sortBy)), + helm.ReleaseListOrder(int32(sortOrder)), + ) + if err != nil { return prettyError(err) } diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index 4e82a9eeb..56eee07f3 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -4,18 +4,51 @@ import ( "bytes" "testing" + "github.com/golang/protobuf/ptypes/timestamp" + "k8s.io/helm/pkg/helm" + "k8s.io/helm/pkg/proto/hapi/chart" + "k8s.io/helm/pkg/proto/hapi/release" + rls "k8s.io/helm/pkg/proto/hapi/services" ) -// Stubbed out tests at two diffent layers -// TestList() is testing the command action -// TestListCmd() is testing command line interface +func releaseMock(name string) *release.Release { + date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0} + return &release.Release{ + Name: name, + Info: &release.Info{ + FirstDeployed: &date, + LastDeployed: &date, + Status: &release.Status{Code: release.Status_DEPLOYED}, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "foo", + Version: "0.1.0-beta.1", + }, + Templates: []*chart.Template{ + {Name: "foo.tpl", Data: []byte("Hello")}, + }, + }, + Config: &chart.Config{Raw: `name = "value"`}, + } +} -// TODO mock tiller responses +type fakeReleaseLister struct { + helm.Interface + rels []*release.Release + err error +} -func TestList(t *testing.T) { - helm.Config.ServAddr = ":44134" +func (fl *fakeReleaseLister) ListReleases(opts ...helm.ReleaseListOption) (*rls.ListReleasesResponse, error) { + resp := &rls.ListReleasesResponse{ + Count: int64(len(fl.rels)), + Releases: fl.rels, + } + return resp, fl.err +} +func TestListRun(t *testing.T) { tests := []struct { name string lister *lister @@ -23,21 +56,34 @@ func TestList(t *testing.T) { err bool }{ { - name: "with a release", - lister: &lister{}, - expected: "understood-coral", + name: "with a release", + lister: &lister{ + client: &fakeReleaseLister{ + rels: []*release.Release{ + releaseMock("thomas-guide"), + }, + }, + }, + expected: "thomas-guide", }, { - name: "list --long", - lister: &lister{long: true}, - expected: "NAME \tUPDATED \tSTATUS \tCHART \nunderstood-coral\tTue Jun 28 12:29:54 2016\tDEPLOYED\tnginx-0.1.0", + name: "list --long", + lister: &lister{ + client: &fakeReleaseLister{ + rels: []*release.Release{ + releaseMock("atlas"), + }, + }, + long: true, + }, + expected: "NAME \tUPDATED \tSTATUS \tCHART \natlas\tFri Sep 2 15:04:05 1977\tDEPLOYED\tfoo-0.1.0-beta.1", }, } var buf bytes.Buffer for _, tt := range tests { tt.lister.out = &buf - err := tt.lister.run([]string{}) + err := tt.lister.run() if (err != nil) != tt.err { t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) } @@ -50,29 +96,38 @@ func TestList(t *testing.T) { } func TestListCmd(t *testing.T) { - helm.Config.ServAddr = ":44134" - tests := []struct { name string args []string flags map[string]string + client helm.Interface expected string err bool }{ { - name: "with a release", - expected: "understood-coral", + name: "with a release", + client: &fakeReleaseLister{ + rels: []*release.Release{ + releaseMock("thomas-guide"), + }, + }, + expected: "thomas-guide", }, { - name: "list --long", - flags: map[string]string{"long": "1"}, - expected: "NAME \tUPDATED \tSTATUS \tCHART \nunderstood-coral\tTue Jun 28 12:29:54 2016\tDEPLOYED\tnginx-0.1.0", + name: "list --long", + flags: map[string]string{"long": "1"}, + client: &fakeReleaseLister{ + rels: []*release.Release{ + releaseMock("atlas"), + }, + }, + expected: "NAME \tUPDATED \tSTATUS \tCHART \natlas\tFri Sep 2 15:04:05 1977\tDEPLOYED\tfoo-0.1.0-beta.1", }, } var buf bytes.Buffer for _, tt := range tests { - cmd := newListCmd(&buf) + cmd := newListCmd(tt.client, &buf) for flag, value := range tt.flags { cmd.Flags().Set(flag, value) } diff --git a/pkg/helm/interface.go b/pkg/helm/interface.go new file mode 100644 index 000000000..7919adb8d --- /dev/null +++ b/pkg/helm/interface.go @@ -0,0 +1,30 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + rls "k8s.io/helm/pkg/proto/hapi/services" +) + +// Interface for helm client for mocking in tests +type Interface interface { + ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) + InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) + DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) + ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) + UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) +}