feat(test): add some completion tests

Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca>
pull/7323/head
Marc Khouzam 6 years ago
parent 90548c591d
commit 0095e32001

@ -0,0 +1,88 @@
/*
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"
"testing"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/release"
helmtime "helm.sh/helm/v3/pkg/time"
)
func outputFlagCompletionTest(t *testing.T, cmdName string) {
releasesMockWithStatus := func(info *release.Info, hooks ...*release.Hook) []*release.Release {
info.LastDeployed = helmtime.Unix(1452902400, 0).UTC()
return []*release.Release{{
Name: "athos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "porthos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "aramis",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "dartagnan",
Namespace: "gascony",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}}
}
tests := []cmdTestCase{{
name: "completion for output flag long and before arg",
cmd: fmt.Sprintf("__complete %s --output ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag long and after arg",
cmd: fmt.Sprintf("__complete %s aramis --output ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag short and before arg",
cmd: fmt.Sprintf("__complete %s -o ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for output flag short and after arg",
cmd: fmt.Sprintf("__complete %s aramis -o ''", cmdName),
golden: "output/output-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}}
runTestCmd(t, tests)
}

@ -41,3 +41,7 @@ func TestGetCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetAllRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get all")
}

@ -36,3 +36,7 @@ func TestGetHooks(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetHooksRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get hooks")
}

@ -36,3 +36,7 @@ func TestGetManifest(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetManifestRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get manifest")
}

@ -36,3 +36,7 @@ func TestGetNotesCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetNotesRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get notes")
}

@ -52,3 +52,11 @@ func TestGetValuesCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestGetValuesRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "get values")
}
func TestGetValuesOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "get values")
}

@ -18,6 +18,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
@ -96,11 +97,39 @@ func storageFixture() *storage.Storage {
return storage.Init(driver.NewMemory())
}
// go-shellwords does not handle empty arguments properly
// https://github.com/mattn/go-shellwords/issues/5#issuecomment-573431458
//
// This method checks if the last argument was an empty one,
// and if go-shellwords missed it, we add it ourselves.
//
// This is important for completion tests as completion often
// uses an empty last parameter.
func checkLastEmpty(in string, out []string) []string {
lastIndex := len(in) - 1
if lastIndex >= 1 && (in[lastIndex] == '"' && in[lastIndex-1] == '"' ||
in[lastIndex] == '\'' && in[lastIndex-1] == '\'') {
// The last parameter of 'in' was empty ("" or ''), let's make sure it was detected.
if len(out) > 0 && out[len(out)-1] != "" {
// Bug from go-shellwords:
// 'out' does not have the empty parameter. We add it ourselves as a workaround.
out = append(out, "")
} else {
fmt.Println("WARNING: go-shellwords seems to have been fixed. This workaround can be removed.")
}
}
return out
}
func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, string, error) {
args, err := shellwords.Parse(cmd)
if err != nil {
return nil, "", err
}
// Workaround the bug in shellwords
args = checkLastEmpty(cmd, args)
buf := new(bytes.Buffer)
actionConfig := &action.Configuration{

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"fmt"
"testing"
"helm.sh/helm/v3/pkg/release"
@ -68,3 +69,42 @@ func TestHistoryCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestHistoryOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "history")
}
func revisionFlagCompletionTest(t *testing.T, cmdName string) {
mk := func(name string, vers int, status release.Status) *release.Release {
return release.Mock(&release.MockReleaseOptions{
Name: name,
Version: vers,
Status: status,
})
}
releases := []*release.Release{
mk("musketeers", 11, release.StatusDeployed),
mk("musketeers", 10, release.StatusSuperseded),
mk("musketeers", 9, release.StatusSuperseded),
mk("musketeers", 8, release.StatusSuperseded),
}
tests := []cmdTestCase{{
name: "completion for revision flag",
cmd: fmt.Sprintf("__complete %s musketeers --revision ''", cmdName),
rels: releases,
golden: "output/revision-comp.txt",
}, {
name: "completion for revision flag with too few args",
cmd: fmt.Sprintf("__complete %s --revision ''", cmdName),
rels: releases,
golden: "output/revision-wrong-args-comp.txt",
}, {
name: "completion for revision flag with too many args",
cmd: fmt.Sprintf("__complete %s three musketeers --revision ''", cmdName),
rels: releases,
golden: "output/revision-wrong-args-comp.txt",
}}
runTestCmd(t, tests)
}

@ -193,3 +193,7 @@ func TestInstall(t *testing.T) {
runTestActionCmd(t, tests)
}
func TestInstallOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "install")
}

@ -206,3 +206,7 @@ func TestListCmd(t *testing.T) {
}}
runTestCmd(t, tests)
}
func TestListOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "list")
}

@ -0,0 +1,25 @@
/*
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 (
"testing"
)
func TestRepoListOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "repo list")
}

@ -232,7 +232,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
newDocsCmd(out),
// Setup the special hidden __complete command to allow for dynamic auto-completion
completion.NewCompleteCmd(settings),
completion.NewCompleteCmd(settings, out),
)
// Add annotation to flags for which we can generate completion choices

@ -49,5 +49,8 @@ func TestSearchHubCmd(t *testing.T) {
t.Log(out)
t.Log(expected)
}
}
func TestSearchHubOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "search hub")
}

@ -83,3 +83,7 @@ func TestSearchRepositoriesCmd(t *testing.T) {
}
runTestCmd(t, tests)
}
func TestSearchRepoOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "search repo")
}

@ -108,3 +108,66 @@ func mustParseTime(t string) helmtime.Time {
res, _ := helmtime.Parse(time.RFC3339, t)
return res
}
func TestStatusCompletion(t *testing.T) {
releasesMockWithStatus := func(info *release.Info, hooks ...*release.Hook) []*release.Release {
info.LastDeployed = helmtime.Unix(1452902400, 0).UTC()
return []*release.Release{{
Name: "athos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "porthos",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "aramis",
Namespace: "default",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}, {
Name: "dartagnan",
Namespace: "gascony",
Info: info,
Chart: &chart.Chart{},
Hooks: hooks,
}}
}
tests := []cmdTestCase{{
name: "completion for status",
cmd: "__complete status a",
golden: "output/status-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for status with too many arguments",
cmd: "__complete status dartagnan ''",
golden: "output/status-wrong-args-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}, {
name: "completion for status with too many arguments",
cmd: "__complete status --debug a",
golden: "output/status-comp.txt",
rels: releasesMockWithStatus(&release.Info{
Status: release.StatusDeployed,
}),
}}
runTestCmd(t, tests)
}
func TestStatusRevisionCompletion(t *testing.T) {
revisionFlagCompletionTest(t, "status")
}
func TestStatusOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "status")
}

@ -0,0 +1,4 @@
table
json
yaml
:0

@ -0,0 +1,3 @@
aramis
athos
:4

@ -258,3 +258,7 @@ func prepareMockRelease(releaseName string, t *testing.T) (func(n string, v int,
return relMock, ch, chartPath
}
func TestUpgradeOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "upgrade")
}

@ -18,6 +18,7 @@ package completion
import (
"errors"
"fmt"
"io"
"log"
"os"
"strings"
@ -111,7 +112,7 @@ func (d BashCompDirective) string() string {
}
// NewCompleteCmd add a special hidden command that an be used to request completions
func NewCompleteCmd(settings *cli.EnvSettings) *cobra.Command {
func NewCompleteCmd(settings *cli.EnvSettings, out io.Writer) *cobra.Command {
debug = settings.Debug
return &cobra.Command{
Use: fmt.Sprintf("%s [command-line]", CompRequestCmd),
@ -169,14 +170,14 @@ func NewCompleteCmd(settings *cli.EnvSettings) *cobra.Command {
completions, directive := completionFn(finalCmd, argsWoFlags, toComplete)
for _, comp := range completions {
// Print each possible completion to stdout for the completion script to consume.
fmt.Println(comp)
fmt.Fprintln(out, comp)
}
// As the last printout, print the completion directive for the
// completion script to parse.
// The directive integer must be that last character following a single :
// The completion script expects :directive
fmt.Printf("\n:%d\n", directive)
fmt.Fprintln(out, fmt.Sprintf(":%d", directive))
// Print some helpful info to stderr for the user to understand.
// Output from stderr should be ignored from the completion script.

Loading…
Cancel
Save