helmfile/cmd/root_test.go

139 lines
4.1 KiB
Go

package cmd
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/helmfile/helmfile/pkg/config"
"github.com/helmfile/helmfile/pkg/errors"
"github.com/helmfile/helmfile/pkg/helmexec"
)
func TestToCLIError(t *testing.T) {
g := config.NewGlobalImpl(&config.GlobalOptions{})
tests := []struct {
name string
err error
wantNil bool
wantExitCode int
wantMsgContains string
}{
{
name: "nil error returns nil",
err: nil,
wantNil: true,
},
{
name: "helmexec.ExitError returns correct exit code",
err: helmexec.ExitError{
Message: "helm command failed",
Code: 7,
},
wantExitCode: 7,
wantMsgContains: "helm command failed",
},
{
name: "wrapped helmexec.ExitError preserves exit code",
err: fmt.Errorf("helm version failed: %w", helmexec.ExitError{Message: "exit status 7", Code: 7}),
wantExitCode: 7,
wantMsgContains: "exit status 7",
},
{
name: "unknown error type returns exit code 1 without panic",
err: fmt.Errorf("some unexpected error"),
wantExitCode: 1,
wantMsgContains: "unexpected error",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Should never panic
var result error
assert.NotPanics(t, func() {
result = toCLIError(g, tt.err)
})
if tt.wantNil {
assert.NoError(t, result)
return
}
assert.Error(t, result)
exitErr, ok := result.(*errors.ExitError)
assert.True(t, ok, "expected *errors.ExitError, got %T", result)
assert.Equal(t, tt.wantExitCode, exitErr.ExitCode())
assert.Contains(t, exitErr.Error(), tt.wantMsgContains)
})
}
}
func TestSelectorFlagCompletion_NonDirKey(t *testing.T) {
// For any selector value that is not a dir= prefix, completion should
// suppress file completion and return no suggestions.
cases := []string{"", "name=", "name=foo", "tier=backend,name", "dir"}
for _, in := range cases {
t.Run(in, func(t *testing.T) {
suggestions, dir := selectorFlagCompletion(nil, nil, in)
assert.Nil(t, suggestions)
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, dir)
})
}
}
func TestSelectorFlagCompletion_DirEnumeratesDirectories(t *testing.T) {
// Set up a temp tree with two subdirs and one file. Completion against
// `dir=` should suggest only the subdirs, prefixed with `dir=`.
root := t.TempDir()
for _, sub := range []string{"apps", "infra"} {
assert.NoError(t, os.MkdirAll(filepath.Join(root, sub), 0o755))
}
assert.NoError(t, os.WriteFile(filepath.Join(root, "helmfile.yaml"), []byte("releases: []"), 0o644))
prev, err := os.Getwd()
assert.NoError(t, err)
assert.NoError(t, os.Chdir(root))
t.Cleanup(func() { _ = os.Chdir(prev) })
suggestions, _ := selectorFlagCompletion(nil, nil, "dir=")
assert.ElementsMatch(t, []string{"dir=apps", "dir=infra"}, suggestions)
}
func TestSelectorFlagCompletion_DirPartialPath(t *testing.T) {
root := t.TempDir()
for _, sub := range []string{"apps/opencloud", "apps/openproject", "apps/xwiki"} {
assert.NoError(t, os.MkdirAll(filepath.Join(root, sub), 0o755))
}
prev, err := os.Getwd()
assert.NoError(t, err)
assert.NoError(t, os.Chdir(root))
t.Cleanup(func() { _ = os.Chdir(prev) })
suggestions, _ := selectorFlagCompletion(nil, nil, "dir=apps/op")
assert.ElementsMatch(t, []string{"dir=apps/opencloud", "dir=apps/openproject"}, suggestions)
}
func TestSelectorFlagCompletion_DirCarriesOverPriorGroups(t *testing.T) {
root := t.TempDir()
assert.NoError(t, os.MkdirAll(filepath.Join(root, "apps"), 0o755))
prev, err := os.Getwd()
assert.NoError(t, err)
assert.NoError(t, os.Chdir(root))
t.Cleanup(func() { _ = os.Chdir(prev) })
suggestions, _ := selectorFlagCompletion(nil, nil, "name=foo,dir=")
assert.ElementsMatch(t, []string{"name=foo,dir=apps"}, suggestions)
}
func TestSelectorFlagCompletion_NonexistentDirReturnsNoSuggestions(t *testing.T) {
suggestions, dir := selectorFlagCompletion(nil, nil, "dir=/does/not/exist/")
assert.Nil(t, suggestions)
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, dir)
}