diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index 08d3b0383..865ff63d3 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -17,85 +17,36 @@ limitations under the License. package main import ( - "fmt" "io" - "github.com/pkg/errors" "github.com/spf13/cobra" - "k8s.io/helm/cmd/helm/require" - "k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/helm" ) const releaseTestDesc = ` -The test command runs the tests for a release. +This command consists of multiple subcommands to run and manage tests +performed on a release. -The argument this command takes is the name of a deployed release. -The tests to be run are defined in the chart that was installed. -` +For now, it can be used to run tests for a given release. More +subcommands will be added in future iterations of this command. -type releaseTestOptions struct { - name string - client helm.Interface - timeout int64 - cleanup bool -} +Example usage: + $ helm test run [RELEASE] -func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { - o := &releaseTestOptions{client: c} +` +func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "test [RELEASE]", - Short: "test a release", + Use: "test", + Short: "run and manage tests on a release", Long: releaseTestDesc, - Args: require.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - o.name = args[0] - o.client = ensureHelmClient(o.client, false) - return o.run(out) - }, } - - f := cmd.Flags() - f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") - f.BoolVar(&o.cleanup, "cleanup", false, "delete test pods upon completion") - - return cmd -} - -func (o *releaseTestOptions) run(out io.Writer) (err error) { - c, errc := o.client.RunReleaseTest( - o.name, - helm.ReleaseTestTimeout(o.timeout), - helm.ReleaseTestCleanup(o.cleanup), + cmd.AddCommand( + newReleaseTestRunCmd(c, out), + newReleaseTestCleanupCmd(c, out), + newReleaseTestResultsCmd(c, out), ) - testErr := &testErr{} - - for { - select { - case err := <-errc: - if err == nil && testErr.failed > 0 { - return testErr.Error() - } - return err - case res, ok := <-c: - if !ok { - break - } - - if res.Status == release.TestRunFailure { - testErr.failed++ - } - fmt.Fprintf(out, res.Msg+"\n") - } - } -} - -type testErr struct { - failed int -} -func (err *testErr) Error() error { - return errors.Errorf("%v test(s) failed", err.failed) + return cmd } diff --git a/cmd/helm/release_testing_cleanup.go b/cmd/helm/release_testing_cleanup.go new file mode 100644 index 000000000..6248f63d2 --- /dev/null +++ b/cmd/helm/release_testing_cleanup.go @@ -0,0 +1,59 @@ +/* +Copyright The Helm Authors. + +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 main + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + "k8s.io/helm/cmd/helm/require" + "k8s.io/helm/pkg/helm" +) + +const releaseTestCleanupDesc = ` +This command deletes the all test pods for the given release. The argument +this command takes is the name of a deployed release. + +Example usage: + $ helm test cleanup [RELEASE] +` + +type releaseTestCleanupOptions struct { + name string + client helm.Interface +} + +func newReleaseTestCleanupCmd(c helm.Interface, out io.Writer) *cobra.Command { + o := &releaseTestCleanupOptions{client: c} + + cmd := &cobra.Command{ + Use: "cleanup [RELEASE]", + Short: "delete test pods for a release", + Long: releaseTestCleanupDesc, + Args: require.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + o.name = args[0] + o.client = ensureHelmClient(o.client, false) + fmt.Fprintf(out, "NOT IMPLEMENTED YET\n") + return nil + }, + } + + return cmd +} diff --git a/cmd/helm/release_testing_results.go b/cmd/helm/release_testing_results.go new file mode 100644 index 000000000..eeeefab7b --- /dev/null +++ b/cmd/helm/release_testing_results.go @@ -0,0 +1,59 @@ +/* +Copyright The Helm Authors. + +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 main + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + "k8s.io/helm/cmd/helm/require" + "k8s.io/helm/pkg/helm" +) + +const releaseTestResultsDesc = ` +This command prints the results of the last test run execution for a +given release. + +Example usage: + $ helm test results: [RELEASE] +` + +type releaseTestResultsOptions struct { + name string + client helm.Interface +} + +func newReleaseTestResultsCmd(c helm.Interface, out io.Writer) *cobra.Command { + o := &releaseTestResultsOptions{client: c} + + cmd := &cobra.Command{ + Use: "results [RELEASE]", + Short: "show latest test results for a release", + Long: releaseTestResultsDesc, + Args: require.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + o.name = args[0] + o.client = ensureHelmClient(o.client, false) + fmt.Fprintf(out, "NOT IMPLEMENTED YET") + return nil + }, + } + + return cmd +} diff --git a/cmd/helm/release_testing_run.go b/cmd/helm/release_testing_run.go new file mode 100644 index 000000000..b5ad2d58b --- /dev/null +++ b/cmd/helm/release_testing_run.go @@ -0,0 +1,103 @@ +/* +Copyright The Helm Authors. + +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 main + +import ( + "fmt" + "io" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "k8s.io/helm/cmd/helm/require" + "k8s.io/helm/pkg/hapi/release" + "k8s.io/helm/pkg/helm" +) + +const releaseTestRunDesc = ` +This command executes the tests for the given release. The argument this +command takes is the name of a deployed release. The tests to be run are +defined in the chart that was installed. + +Example usage: + $ helm test run [RELEASE] +` + +type releaseTestRunOptions struct { + name string + client helm.Interface + timeout int64 + cleanup bool +} + +func newReleaseTestRunCmd(c helm.Interface, out io.Writer) *cobra.Command { + o := &releaseTestRunOptions{client: c} + + cmd := &cobra.Command{ + Use: "run [RELEASE]", + Short: "execute tests for a release", + Long: releaseTestRunDesc, + Args: require.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + o.name = args[0] + o.client = ensureHelmClient(o.client, false) + return o.run(out) + }, + } + + f := cmd.Flags() + f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.BoolVar(&o.cleanup, "cleanup", false, "delete test pods upon completion") + + return cmd +} + +func (o *releaseTestRunOptions) run(out io.Writer) (err error) { + c, errc := o.client.RunReleaseTest( + o.name, + helm.ReleaseTestTimeout(o.timeout), + helm.ReleaseTestCleanup(o.cleanup), + ) + testErr := &testErr{} + + for { + select { + case err := <-errc: + if err == nil && testErr.failed > 0 { + return testErr.Error() + } + return err + case res, ok := <-c: + if !ok { + break + } + + if res.Status == release.TestRunFailure { + testErr.failed++ + } + fmt.Fprintf(out, res.Msg+"\n") + } + } +} + +type testErr struct { + failed int +} + +func (err *testErr) Error() error { + return errors.Errorf("%v test(s) failed", err.failed) +} diff --git a/cmd/helm/release_testing_test.go b/cmd/helm/release_testing_run_test.go similarity index 89% rename from cmd/helm/release_testing_test.go rename to cmd/helm/release_testing_run_test.go index 28be860b4..5e16e7ab7 100644 --- a/cmd/helm/release_testing_test.go +++ b/cmd/helm/release_testing_run_test.go @@ -25,34 +25,34 @@ import ( func TestReleaseTesting(t *testing.T) { tests := []cmdTestCase{{ name: "basic test", - cmd: "test example-release", + cmd: "test run example-release", testRunStatus: map[string]release.TestRunStatus{"PASSED: green lights everywhere": release.TestRunSuccess}, golden: "output/test.txt", }, { name: "test failure", - cmd: "test example-fail", + cmd: "test run example-fail", testRunStatus: map[string]release.TestRunStatus{"FAILURE: red lights everywhere": release.TestRunFailure}, wantError: true, golden: "output/test-failure.txt", }, { name: "test unknown", - cmd: "test example-unknown", + cmd: "test run example-unknown", testRunStatus: map[string]release.TestRunStatus{"UNKNOWN: yellow lights everywhere": release.TestRunUnknown}, golden: "output/test-unknown.txt", }, { name: "test error", - cmd: "test example-error", + cmd: "test run example-error", testRunStatus: map[string]release.TestRunStatus{"ERROR: yellow lights everywhere": release.TestRunFailure}, wantError: true, golden: "output/test-error.txt", }, { name: "test running", - cmd: "test example-running", + cmd: "test run example-running", testRunStatus: map[string]release.TestRunStatus{"RUNNING: things are happpeningggg": release.TestRunRunning}, golden: "output/test-running.txt", }, { name: "multiple tests example", - cmd: "test example-suite", + cmd: "test run example-suite", testRunStatus: map[string]release.TestRunStatus{ "RUNNING: things are happpeningggg": release.TestRunRunning, "PASSED: party time": release.TestRunSuccess,