tests: Add/Fix tests for new flag and fix docker wait, make fmt issue
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
parent
1c59d0a539
commit
acaaa34d69
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/helmfile/helmfile/pkg/common"
|
||||||
"github.com/helmfile/helmfile/pkg/exectest"
|
"github.com/helmfile/helmfile/pkg/exectest"
|
||||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||||
|
|
@ -416,3 +417,138 @@ releases:
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDiffWithIncludeCRDs(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
includeCRDs common.BoolFlag
|
||||||
|
skipCRDs common.BoolFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
type testcase struct {
|
||||||
|
fields fields
|
||||||
|
ns string
|
||||||
|
error string
|
||||||
|
selectors []string
|
||||||
|
diffed []exectest.Release
|
||||||
|
}
|
||||||
|
|
||||||
|
check := func(t *testing.T, tc testcase) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
wantDiffs := tc.diffed
|
||||||
|
|
||||||
|
var helm = &exectest.Helm{
|
||||||
|
FailOnUnexpectedList: true,
|
||||||
|
FailOnUnexpectedDiff: true,
|
||||||
|
DiffMutex: &sync.Mutex{},
|
||||||
|
ChartsMutex: &sync.Mutex{},
|
||||||
|
ReleasesMutex: &sync.Mutex{},
|
||||||
|
Helm3: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := runWithLogCapture(t, "debug", func(t *testing.T, logger *zap.SugaredLogger) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
valsRuntime, err := vals.New(vals.Options{CacheSize: 32})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error creating vals runtime: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
files := map[string]string{
|
||||||
|
"/path/to/helmfile.yaml": `
|
||||||
|
releases:
|
||||||
|
- name: include-crds
|
||||||
|
chart: incubator/raw
|
||||||
|
namespace: default
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
app := appWithFs(&App{
|
||||||
|
OverrideHelmBinary: DefaultHelmBinary,
|
||||||
|
fs: filesystem.DefaultFileSystem(),
|
||||||
|
OverrideKubeContext: "default",
|
||||||
|
Env: "default",
|
||||||
|
Logger: logger,
|
||||||
|
helms: map[helmKey]helmexec.Interface{
|
||||||
|
createHelmKey("helm", "default"): helm,
|
||||||
|
},
|
||||||
|
valsRuntime: valsRuntime,
|
||||||
|
}, files)
|
||||||
|
|
||||||
|
if tc.ns != "" {
|
||||||
|
app.Namespace = tc.ns
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.selectors != nil {
|
||||||
|
app.Selectors = tc.selectors
|
||||||
|
}
|
||||||
|
|
||||||
|
diffConfig := NewApplyConfigWithDefaults(&applyConfig{
|
||||||
|
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||||
|
concurrency: 1,
|
||||||
|
logger: logger,
|
||||||
|
includeCRDs: tc.fields.includeCRDs,
|
||||||
|
skipCRDs: tc.fields.skipCRDs,
|
||||||
|
})
|
||||||
|
diffErr := app.Diff(diffConfig)
|
||||||
|
|
||||||
|
var gotErr string
|
||||||
|
if diffErr != nil {
|
||||||
|
gotErr = diffErr.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if d := cmp.Diff(tc.error, gotErr); d != "" {
|
||||||
|
t.Fatalf("unexpected error: want (-), got (+): %s", d)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, wantDiffs, helm.Diffed)
|
||||||
|
})
|
||||||
|
|
||||||
|
testhelper.RequireLog(t, "app_diff_test", bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("include-crds", func(t *testing.T) {
|
||||||
|
includeCRDs := common.NewBoolFlag(false)
|
||||||
|
includeCRDs.Set(true)
|
||||||
|
|
||||||
|
check(t, testcase{
|
||||||
|
fields: fields{
|
||||||
|
skipCRDs: common.NewBoolFlag(false),
|
||||||
|
includeCRDs: includeCRDs,
|
||||||
|
},
|
||||||
|
diffed: []exectest.Release{
|
||||||
|
{Name: "include-crds", Flags: []string{"--kube-context", "default", "--namespace", "default", "--reset-values", "--include-crds"}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("include-or-skip-crds-unset", func(t *testing.T) {
|
||||||
|
includeCRDs := common.NewBoolFlag(false)
|
||||||
|
includeCRDs.Set(true)
|
||||||
|
|
||||||
|
check(t, testcase{
|
||||||
|
fields: fields{
|
||||||
|
skipCRDs: common.NewBoolFlag(false),
|
||||||
|
includeCRDs: common.NewBoolFlag(false),
|
||||||
|
},
|
||||||
|
diffed: []exectest.Release{
|
||||||
|
{Name: "include-crds", Flags: []string{"--kube-context", "default", "--namespace", "default", "--reset-values"}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("skip-crds", func(t *testing.T) {
|
||||||
|
skipCRDs := common.NewBoolFlag(false)
|
||||||
|
skipCRDs.Set(true)
|
||||||
|
|
||||||
|
check(t, testcase{
|
||||||
|
fields: fields{
|
||||||
|
skipCRDs: skipCRDs,
|
||||||
|
includeCRDs: common.NewBoolFlag(false),
|
||||||
|
},
|
||||||
|
diffed: []exectest.Release{
|
||||||
|
{Name: "include-crds", Flags: []string{"--kube-context", "default", "--namespace", "default", "--reset-values", "--skip-crds"}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2172,11 +2172,18 @@ func (c configImpl) IncludeCRDs() bool {
|
||||||
return c.includeCRDs.Value()
|
return c.includeCRDs.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldIncludeCRDs determines if CRDs should be included in the operation.
|
||||||
|
// It returns true only when:
|
||||||
|
// - includeCRDs flag is explicitly provided on the command line and set to true
|
||||||
|
// - AND skipCRDs flag is not provided on the command line
|
||||||
|
//
|
||||||
|
// This ensures that CRDs are only included when explicitly requested and not
|
||||||
|
// contradicted by the skipCRDs flag.
|
||||||
func (c configImpl) ShouldIncludeCRDs() bool {
|
func (c configImpl) ShouldIncludeCRDs() bool {
|
||||||
includeCRDsExplicit := c.includeCRDs.WasExplicitlySet() && c.includeCRDs.Value()
|
includeCRDsExplicit := c.includeCRDs.WasExplicitlySet() && c.includeCRDs.Value()
|
||||||
skipCRDsExplicit := c.skipCRDs.WasExplicitlySet() && !c.skipCRDs.Value()
|
skipCRDsNotProvided := !c.skipCRDs.WasExplicitlySet()
|
||||||
|
|
||||||
return includeCRDsExplicit || skipCRDsExplicit
|
return includeCRDsExplicit && skipCRDsNotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c configImpl) SkipRefresh() bool {
|
func (c configImpl) SkipRefresh() bool {
|
||||||
|
|
@ -2324,203 +2331,210 @@ func NewApplyConfigWithDefaults(existing *applyConfig) *applyConfig {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Args() string {
|
func (c applyConfig) Args() string {
|
||||||
return a.args
|
return c.args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Cascade() string {
|
func (c applyConfig) Cascade() string {
|
||||||
return a.cascade
|
return c.cascade
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Wait() bool {
|
func (c applyConfig) Wait() bool {
|
||||||
return a.wait
|
return c.wait
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) WaitRetries() int {
|
func (c applyConfig) WaitRetries() int {
|
||||||
return a.waitRetries
|
return c.waitRetries
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) WaitForJobs() bool {
|
func (c applyConfig) WaitForJobs() bool {
|
||||||
return a.waitForJobs
|
return c.waitForJobs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Values() []string {
|
func (c applyConfig) Values() []string {
|
||||||
return a.values
|
return c.values
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Set() []string {
|
func (c applyConfig) Set() []string {
|
||||||
return a.set
|
return c.set
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Validate() bool {
|
func (c applyConfig) Validate() bool {
|
||||||
return a.validate
|
return c.validate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipCleanup() bool {
|
func (c applyConfig) SkipCleanup() bool {
|
||||||
return a.skipCleanup
|
return c.skipCleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipCRDs() bool {
|
func (c applyConfig) SkipCRDs() bool {
|
||||||
return a.skipCRDs.Value()
|
return c.skipCRDs.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeCRDs() bool {
|
func (c applyConfig) IncludeCRDs() bool {
|
||||||
return a.includeCRDs.Value()
|
return c.includeCRDs.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldIncludeCRDs determines if CRDs should be included in the operation.
|
||||||
|
// It returns true only when:
|
||||||
|
// - includeCRDs flag is explicitly provided on the command line and set to true
|
||||||
|
// - AND skipCRDs flag is not provided on the command line
|
||||||
|
//
|
||||||
|
// This ensures that CRDs are only included when explicitly requested and not
|
||||||
|
// contradicted by the skipCRDs flag.
|
||||||
func (c applyConfig) ShouldIncludeCRDs() bool {
|
func (c applyConfig) ShouldIncludeCRDs() bool {
|
||||||
includeCRDsExplicit := c.includeCRDs.WasExplicitlySet() && c.includeCRDs.Value()
|
includeCRDsExplicit := c.includeCRDs.WasExplicitlySet() && c.includeCRDs.Value()
|
||||||
skipCRDsExplicit := c.skipCRDs.WasExplicitlySet() && !c.skipCRDs.Value()
|
skipCRDsNotProvided := !c.skipCRDs.WasExplicitlySet()
|
||||||
|
|
||||||
return includeCRDsExplicit || skipCRDsExplicit
|
return includeCRDsExplicit && skipCRDsNotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipDeps() bool {
|
func (c applyConfig) SkipDeps() bool {
|
||||||
return a.skipDeps
|
return c.skipDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipRefresh() bool {
|
func (c applyConfig) SkipRefresh() bool {
|
||||||
return a.skipRefresh
|
return c.skipRefresh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipNeeds() bool {
|
func (c applyConfig) SkipNeeds() bool {
|
||||||
return a.skipNeeds
|
return c.skipNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeNeeds() bool {
|
func (c applyConfig) IncludeNeeds() bool {
|
||||||
return a.includeNeeds || a.IncludeTransitiveNeeds()
|
return c.includeNeeds || c.IncludeTransitiveNeeds()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeTransitiveNeeds() bool {
|
func (c applyConfig) IncludeTransitiveNeeds() bool {
|
||||||
return a.includeTransitiveNeeds
|
return c.includeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeTests() bool {
|
func (c applyConfig) IncludeTests() bool {
|
||||||
return a.includeTests
|
return c.includeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Suppress() []string {
|
func (c applyConfig) Suppress() []string {
|
||||||
return a.suppress
|
return c.suppress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SuppressSecrets() bool {
|
func (c applyConfig) SuppressSecrets() bool {
|
||||||
return a.suppressSecrets
|
return c.suppressSecrets
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) ShowSecrets() bool {
|
func (c applyConfig) ShowSecrets() bool {
|
||||||
return a.showSecrets
|
return c.showSecrets
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) NoHooks() bool {
|
func (c applyConfig) NoHooks() bool {
|
||||||
return a.noHooks
|
return c.noHooks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SuppressDiff() bool {
|
func (c applyConfig) SuppressDiff() bool {
|
||||||
return a.suppressDiff
|
return c.suppressDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Color() bool {
|
func (c applyConfig) Color() bool {
|
||||||
return a.color
|
return c.color
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) NoColor() bool {
|
func (c applyConfig) NoColor() bool {
|
||||||
return a.noColor
|
return c.noColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Context() int {
|
func (c applyConfig) Context() int {
|
||||||
return a.context
|
return c.context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) DiffOutput() string {
|
func (c applyConfig) DiffOutput() string {
|
||||||
return a.diffOutput
|
return c.diffOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Concurrency() int {
|
func (c applyConfig) Concurrency() int {
|
||||||
return a.concurrency
|
return c.concurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) DetailedExitcode() bool {
|
func (c applyConfig) DetailedExitcode() bool {
|
||||||
return a.detailedExitcode
|
return c.detailedExitcode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) StripTrailingCR() bool {
|
func (c applyConfig) StripTrailingCR() bool {
|
||||||
return a.stripTrailingCR
|
return c.stripTrailingCR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Interactive() bool {
|
func (c applyConfig) Interactive() bool {
|
||||||
return a.interactive
|
return c.interactive
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Logger() *zap.SugaredLogger {
|
func (c applyConfig) Logger() *zap.SugaredLogger {
|
||||||
return a.logger
|
return c.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipDiffOnInstall() bool {
|
func (c applyConfig) SkipDiffOnInstall() bool {
|
||||||
return a.skipDiffOnInstall
|
return c.skipDiffOnInstall
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SyncArgs() string {
|
func (c applyConfig) SyncArgs() string {
|
||||||
return a.syncArgs
|
return c.syncArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) DiffArgs() string {
|
func (c applyConfig) DiffArgs() string {
|
||||||
return a.diffArgs
|
return c.diffArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
// helmfile-template-only flags
|
// helmfile-template-only flags
|
||||||
func (a applyConfig) SkipTests() bool {
|
func (c applyConfig) SkipTests() bool {
|
||||||
return a.skipTests
|
return c.skipTests
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) OutputDir() string {
|
func (c applyConfig) OutputDir() string {
|
||||||
return a.outputDir
|
return c.outputDir
|
||||||
}
|
}
|
||||||
func (a applyConfig) OutputDirTemplate() string {
|
func (c applyConfig) OutputDirTemplate() string {
|
||||||
return a.outputDirTemplate
|
return c.outputDirTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) ReuseValues() bool {
|
func (c applyConfig) ReuseValues() bool {
|
||||||
return a.reuseValues
|
return c.reuseValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) ResetValues() bool {
|
func (c applyConfig) ResetValues() bool {
|
||||||
return !a.reuseValues
|
return !c.reuseValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) PostRenderer() string {
|
func (c applyConfig) PostRenderer() string {
|
||||||
return a.postRenderer
|
return c.postRenderer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) PostRendererArgs() []string {
|
func (c applyConfig) PostRendererArgs() []string {
|
||||||
return a.postRendererArgs
|
return c.postRendererArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SuppressOutputLineRegex() []string {
|
func (c applyConfig) SuppressOutputLineRegex() []string {
|
||||||
return a.suppressOutputLineRegex
|
return c.suppressOutputLineRegex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) KubeVersion() string {
|
func (c applyConfig) KubeVersion() string {
|
||||||
return a.kubeVersion
|
return c.kubeVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SkipSchemaValidation() bool {
|
func (c applyConfig) SkipSchemaValidation() bool {
|
||||||
return a.skipSchemaValidation
|
return c.skipSchemaValidation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) ShowOnly() []string {
|
func (c applyConfig) ShowOnly() []string {
|
||||||
return a.showOnly
|
return c.showOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) HideNotes() bool {
|
func (c applyConfig) HideNotes() bool {
|
||||||
return a.hideNotes
|
return c.hideNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) TakeOwnership() bool {
|
func (c applyConfig) TakeOwnership() bool {
|
||||||
return a.takeOwnership
|
return c.takeOwnership
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) SyncReleaseLabels() bool {
|
func (c applyConfig) SyncReleaseLabels() bool {
|
||||||
return a.syncReleaseLabels
|
return c.syncReleaseLabels
|
||||||
}
|
}
|
||||||
|
|
||||||
type depsConfig struct {
|
type depsConfig struct {
|
||||||
|
|
@ -2528,19 +2542,19 @@ type depsConfig struct {
|
||||||
includeTransitiveNeeds bool
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d depsConfig) SkipRepos() bool {
|
func (c depsConfig) SkipRepos() bool {
|
||||||
return d.skipRepos
|
return c.skipRepos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d depsConfig) IncludeTransitiveNeeds() bool {
|
func (c depsConfig) IncludeTransitiveNeeds() bool {
|
||||||
return d.includeTransitiveNeeds
|
return c.includeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d depsConfig) Args() string {
|
func (c depsConfig) Args() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d depsConfig) Concurrency() int {
|
func (c depsConfig) Concurrency() int {
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4077,10 +4091,10 @@ releases:
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
expected := "NAME NAMESPACE ENABLED INSTALLED LABELS CHART VERSION\n" +
|
expected := "NAME NAMESPACE ENABLED INSTALLED LABELS CHART VERSION\n" +
|
||||||
"myrelease1 testNamespace true false chart:mychart1,common:label,id:myrelease1,name:myrelease1,namespace:testNamespace mychart1\t \n" +
|
"myrelease1 testNamespace true false chart:mychart1,common:label,id:myrelease1,name:myrelease1,namespace:testNamespace mychart1\t \n" +
|
||||||
"myrelease2 testNamespace false true chart:mychart1,common:label,name:myrelease2,namespace:testNamespace mychart1\t \n" +
|
"myrelease2 testNamespace false true chart:mychart1,common:label,name:myrelease2,namespace:testNamespace mychart1\t \n" +
|
||||||
"myrelease3 testNamespace true true chart:mychart1,name:myrelease3,namespace:testNamespace mychart1\t \n" +
|
"myrelease3 testNamespace true true chart:mychart1,name:myrelease3,namespace:testNamespace mychart1\t \n" +
|
||||||
"myrelease4 testNamespace true true chart:mychart1,id:myrelease1,name:myrelease4,namespace:testNamespace mychart1\t \n"
|
"myrelease4 testNamespace true true chart:mychart1,id:myrelease1,name:myrelease4,namespace:testNamespace mychart1\t \n"
|
||||||
|
|
||||||
assert.Equal(t, expected, out)
|
assert.Equal(t, expected, out)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,151 +75,158 @@ func NewDiffConfigWithDefaults(existing *diffConfig) *diffConfig {
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Args() string {
|
func (c diffConfig) Args() string {
|
||||||
return a.args
|
return c.args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) DiffArgs() string {
|
func (c diffConfig) DiffArgs() string {
|
||||||
return a.diffArgs
|
return c.diffArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Values() []string {
|
func (c diffConfig) Values() []string {
|
||||||
return a.values
|
return c.values
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Set() []string {
|
func (c diffConfig) Set() []string {
|
||||||
return a.set
|
return c.set
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Validate() bool {
|
func (c diffConfig) Validate() bool {
|
||||||
return a.validate
|
return c.validate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipCRDs() bool {
|
func (c diffConfig) SkipCRDs() bool {
|
||||||
return a.skipCRDs.Value()
|
return c.skipCRDs.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) IncludeCRDs() bool {
|
func (c diffConfig) IncludeCRDs() bool {
|
||||||
return a.includeCRDs.Value()
|
return c.includeCRDs.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) ShouldIncludeCRDs() bool {
|
// ShouldIncludeCRDs determines if CRDs should be included in the operation.
|
||||||
includeCRDsExplicit := a.includeCRDs.WasExplicitlySet() && a.includeCRDs.Value()
|
// It returns true only when:
|
||||||
skipCRDsExplicit := a.skipCRDs.WasExplicitlySet() && !a.skipCRDs.Value()
|
// - includeCRDs flag is explicitly provided on the command line and set to true
|
||||||
|
// - AND skipCRDs flag is not provided on the command line
|
||||||
|
//
|
||||||
|
// This ensures that CRDs are only included when explicitly requested and not
|
||||||
|
// contradicted by the skipCRDs flag.
|
||||||
|
func (c diffConfig) ShouldIncludeCRDs() bool {
|
||||||
|
includeCRDsExplicit := c.includeCRDs.WasExplicitlySet() && c.includeCRDs.Value()
|
||||||
|
skipCRDsNotProvided := !c.skipCRDs.WasExplicitlySet()
|
||||||
|
|
||||||
return includeCRDsExplicit || skipCRDsExplicit
|
return includeCRDsExplicit && skipCRDsNotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipDeps() bool {
|
func (c diffConfig) SkipDeps() bool {
|
||||||
return a.skipDeps
|
return c.skipDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipRefresh() bool {
|
func (c diffConfig) SkipRefresh() bool {
|
||||||
return a.skipRefresh
|
return c.skipRefresh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) IncludeTests() bool {
|
func (c diffConfig) IncludeTests() bool {
|
||||||
return a.includeTests
|
return c.includeTests
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipNeeds() bool {
|
func (c diffConfig) SkipNeeds() bool {
|
||||||
return a.skipNeeds
|
return c.skipNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) IncludeNeeds() bool {
|
func (c diffConfig) IncludeNeeds() bool {
|
||||||
return a.includeNeeds || a.IncludeTransitiveNeeds()
|
return c.includeNeeds || c.IncludeTransitiveNeeds()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) IncludeTransitiveNeeds() bool {
|
func (c diffConfig) IncludeTransitiveNeeds() bool {
|
||||||
return a.includeTransitiveNeeds
|
return c.includeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Suppress() []string {
|
func (c diffConfig) Suppress() []string {
|
||||||
return a.suppress
|
return c.suppress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SuppressSecrets() bool {
|
func (c diffConfig) SuppressSecrets() bool {
|
||||||
return a.suppressSecrets
|
return c.suppressSecrets
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) ShowSecrets() bool {
|
func (c diffConfig) ShowSecrets() bool {
|
||||||
return a.showSecrets
|
return c.showSecrets
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) NoHooks() bool {
|
func (c diffConfig) NoHooks() bool {
|
||||||
return a.noHooks
|
return c.noHooks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SuppressDiff() bool {
|
func (c diffConfig) SuppressDiff() bool {
|
||||||
return a.suppressDiff
|
return c.suppressDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Color() bool {
|
func (c diffConfig) Color() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) NoColor() bool {
|
func (c diffConfig) NoColor() bool {
|
||||||
return a.noColor
|
return c.noColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Context() int {
|
func (c diffConfig) Context() int {
|
||||||
return a.context
|
return c.context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) DiffOutput() string {
|
func (c diffConfig) DiffOutput() string {
|
||||||
return a.diffOutput
|
return c.diffOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Concurrency() int {
|
func (c diffConfig) Concurrency() int {
|
||||||
return a.concurrency
|
return c.concurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) DetailedExitcode() bool {
|
func (c diffConfig) DetailedExitcode() bool {
|
||||||
return a.detailedExitcode
|
return c.detailedExitcode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) StripTrailingCR() bool {
|
func (c diffConfig) StripTrailingCR() bool {
|
||||||
return a.stripTrailingCR
|
return c.stripTrailingCR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Interactive() bool {
|
func (c diffConfig) Interactive() bool {
|
||||||
return a.interactive
|
return c.interactive
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipDiffOnInstall() bool {
|
func (c diffConfig) SkipDiffOnInstall() bool {
|
||||||
return a.skipDiffOnInstall
|
return c.skipDiffOnInstall
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) Logger() *zap.SugaredLogger {
|
func (c diffConfig) Logger() *zap.SugaredLogger {
|
||||||
return a.logger
|
return c.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) RetainValuesFiles() bool {
|
func (c diffConfig) RetainValuesFiles() bool {
|
||||||
return a.retainValuesFiles
|
return c.retainValuesFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) ReuseValues() bool {
|
func (c diffConfig) ReuseValues() bool {
|
||||||
return a.reuseValues
|
return c.reuseValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) ResetValues() bool {
|
func (c diffConfig) ResetValues() bool {
|
||||||
return !a.reuseValues
|
return !c.reuseValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) PostRenderer() string {
|
func (c diffConfig) PostRenderer() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) PostRendererArgs() []string {
|
func (c diffConfig) PostRendererArgs() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SkipSchemaValidation() bool {
|
func (c diffConfig) SkipSchemaValidation() bool {
|
||||||
return a.skipSchemaValidation
|
return c.skipSchemaValidation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a diffConfig) SuppressOutputLineRegex() []string {
|
func (c diffConfig) SuppressOutputLineRegex() []string {
|
||||||
return a.suppressOutputLineRegex
|
return c.suppressOutputLineRegex
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiff(t *testing.T) {
|
func TestDiff(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
processing file "helmfile.yaml" in directory "."
|
||||||
|
changing working directory to "/path/to"
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
1 release(s) found in helmfile.yaml
|
||||||
|
|
||||||
|
processing 1 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default/default/include-crds
|
||||||
|
|
||||||
|
processing releases in group 1/1: default/default/include-crds
|
||||||
|
changing working directory back to "/path/to"
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
processing file "helmfile.yaml" in directory "."
|
||||||
|
changing working directory to "/path/to"
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
1 release(s) found in helmfile.yaml
|
||||||
|
|
||||||
|
processing 1 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default/default/include-crds
|
||||||
|
|
||||||
|
processing releases in group 1/1: default/default/include-crds
|
||||||
|
changing working directory back to "/path/to"
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
processing file "helmfile.yaml" in directory "."
|
||||||
|
changing working directory to "/path/to"
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
1 release(s) found in helmfile.yaml
|
||||||
|
|
||||||
|
processing 1 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default/default/include-crds
|
||||||
|
|
||||||
|
processing releases in group 1/1: default/default/include-crds
|
||||||
|
changing working directory back to "/path/to"
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||||
"github.com/helmfile/helmfile/pkg/testutil"
|
"github.com/helmfile/helmfile/pkg/testutil"
|
||||||
|
"github.com/helmfile/helmfile/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAppendWaitForJobsFlags(t *testing.T) {
|
func TestAppendWaitForJobsFlags(t *testing.T) {
|
||||||
|
|
@ -432,6 +433,74 @@ func TestAppendTakeOwnershipFlags(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAppendCRDFlags(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
flags []string
|
||||||
|
helm helmexec.Interface
|
||||||
|
helmSpec HelmSpec
|
||||||
|
opt *DiffOpts
|
||||||
|
expected []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no include-crds nor skip-crds provided",
|
||||||
|
args: args{
|
||||||
|
flags: []string{},
|
||||||
|
helm: testutil.NewVersionHelmExec(version.HelmRequiredVersion),
|
||||||
|
opt: &DiffOpts{},
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include-crds set but no skip-crds",
|
||||||
|
args: args{
|
||||||
|
flags: []string{},
|
||||||
|
helm: testutil.NewVersionHelmExec(version.HelmRequiredVersion),
|
||||||
|
opt: &DiffOpts{
|
||||||
|
SkipCRDs: false,
|
||||||
|
IncludeCRDs: true,
|
||||||
|
},
|
||||||
|
expected: []string{"--include-crds"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include-crds and skip-crds set",
|
||||||
|
args: args{
|
||||||
|
flags: []string{},
|
||||||
|
helm: testutil.NewVersionHelmExec(version.HelmRequiredVersion),
|
||||||
|
opt: &DiffOpts{
|
||||||
|
SkipCRDs: true,
|
||||||
|
IncludeCRDs: true,
|
||||||
|
},
|
||||||
|
expected: []string{"--skip-crds"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include-crds not set but skip-crds is",
|
||||||
|
args: args{
|
||||||
|
flags: []string{},
|
||||||
|
helm: testutil.NewVersionHelmExec(version.HelmRequiredVersion),
|
||||||
|
opt: &DiffOpts{
|
||||||
|
SkipCRDs: true,
|
||||||
|
IncludeCRDs: false,
|
||||||
|
},
|
||||||
|
expected: []string{"--skip-crds"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
st := &HelmState{}
|
||||||
|
st.HelmDefaults = tt.args.helmSpec
|
||||||
|
got := st.appendCRDFlags(tt.args.flags, tt.args.opt.SkipCRDs, tt.args.opt.IncludeCRDs)
|
||||||
|
require.Equalf(t, tt.args.expected, got, "appendCRDFlags() = %v, want %v", got, tt.args.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFormatLabels(t *testing.T) {
|
func TestFormatLabels(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
|
|
@ -3477,44 +3477,44 @@ func TestCommonDiffFlags(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonDiffFlags_IncludeCRDs(t *testing.T) {
|
func TestCommonDiffFlags_IncludeCRDs(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
inputOpts *DiffOpts
|
inputOpts *DiffOpts
|
||||||
expected []string
|
expected []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Include CRDs flag is set to true",
|
name: "Include CRDs flag is set to true",
|
||||||
inputOpts: &DiffOpts{
|
inputOpts: &DiffOpts{
|
||||||
IncludeCRDs: true,
|
IncludeCRDs: true,
|
||||||
},
|
},
|
||||||
expected: []string{"--reset-values", "--include-crds"},
|
expected: []string{"--reset-values", "--include-crds"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Include CRDs flag is set to false",
|
name: "Include CRDs flag is set to false",
|
||||||
inputOpts: &DiffOpts{
|
inputOpts: &DiffOpts{
|
||||||
IncludeCRDs: false,
|
IncludeCRDs: false,
|
||||||
},
|
},
|
||||||
expected: []string{"--reset-values"},
|
expected: []string{"--reset-values"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Include CRDs flag not set in options",
|
name: "Include CRDs flag not set in options",
|
||||||
inputOpts: &DiffOpts{},
|
inputOpts: &DiffOpts{},
|
||||||
expected: []string{"--reset-values"},
|
expected: []string{"--reset-values"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
state := &HelmState{}
|
state := &HelmState{}
|
||||||
result := state.commonDiffFlags(false, false, false, []string{}, false, false, false, test.inputOpts)
|
result := state.commonDiffFlags(false, false, false, []string{}, false, false, false, test.inputOpts)
|
||||||
|
|
||||||
// Check if the result contains the expected flags
|
// Check if the result contains the expected flags
|
||||||
if !reflect.DeepEqual(result, test.expected) {
|
if !reflect.DeepEqual(result, test.expected) {
|
||||||
t.Errorf("commonDiffFlags() with IncludeCRDs=%v = %v, want %v",
|
t.Errorf("commonDiffFlags() with IncludeCRDs=%v = %v, want %v",
|
||||||
test.inputOpts.IncludeCRDs, result, test.expected)
|
test.inputOpts.IncludeCRDs, result, test.expected)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendChartDownloadFlags(t *testing.T) {
|
func TestAppendChartDownloadFlags(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Helmfile Test Command Package
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `testcommand` package provides utilities for testing Helmfile commands in a controlled environment. This package simplifies the creation and configuration of command objects for testing purposes, allowing developers to verify command behavior without executing the full application.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### CommandTestHelper
|
||||||
|
|
||||||
|
The core structure that encapsulates the components needed for testing commands:
|
||||||
|
|
||||||
|
- `Cmd`: The Cobra command instance
|
||||||
|
- `Registry`: Flag registry for managing command flags
|
||||||
|
- `Options`: Command-specific options
|
||||||
|
|
||||||
|
### Available Test Commands
|
||||||
|
|
||||||
|
The package provides helper functions to create test instances of the following Helmfile commands:
|
||||||
|
|
||||||
|
- **TestDiffCmd()**: Creates a test instance of the `diff` command
|
||||||
|
- **TestApplyCmd()**: Creates a test instance of the `apply` command
|
||||||
|
- **TestTemplateCmd()**: Creates a test instance of the `template` command
|
||||||
|
- **TestSyncCmd()**: Creates a test instance of the `sync` command
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"github.com/helmfile/helmfile/pkg/testcommand"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMyDiffCommand(t *testing.T) {
|
||||||
|
// Create a test diff command
|
||||||
|
helper := testcommand.TestDiffCmd()
|
||||||
|
|
||||||
|
// Access the command components
|
||||||
|
cmd := helper.Cmd
|
||||||
|
options := helper.Options.(*config.DiffOptions)
|
||||||
|
|
||||||
|
// Set up test flags
|
||||||
|
cmd.Flags().Set("concurrency", "5")
|
||||||
|
|
||||||
|
// Test command behavior
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
Each test command function:
|
||||||
|
|
||||||
|
1. Creates an options factory for the specific command
|
||||||
|
2. Instantiates the command options
|
||||||
|
3. Gets the flag registry
|
||||||
|
4. Creates a Cobra command instance
|
||||||
|
5. Registers the appropriate flags
|
||||||
|
6. Returns a helper with all components
|
||||||
|
|
||||||
|
For the `diff` command, flag values are automatically transferred to the options object.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
This package is intended for testing purposes only and should not be used in production code.
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package testcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/helmfile/helmfile/pkg/config"
|
||||||
|
"github.com/helmfile/helmfile/pkg/factory"
|
||||||
|
"github.com/helmfile/helmfile/pkg/flags"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandTestHelper provides utilities for testing commands
|
||||||
|
type CommandTestHelper struct {
|
||||||
|
Cmd *cobra.Command
|
||||||
|
Registry flags.FlagRegistry
|
||||||
|
Options config.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDiffCmd creates a diff command for testing and returns a helper with its components
|
||||||
|
func TestDiffCmd() *CommandTestHelper {
|
||||||
|
// Create command components
|
||||||
|
optionsFactory := factory.NewDiffOptionsFactory()
|
||||||
|
options := optionsFactory.CreateOptions().(*config.DiffOptions)
|
||||||
|
registry := optionsFactory.GetFlagRegistry()
|
||||||
|
|
||||||
|
// Create command manually
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "diff",
|
||||||
|
Short: "Diff releases defined in state file",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register flags
|
||||||
|
registry.RegisterFlags(cmd)
|
||||||
|
|
||||||
|
// Transfer flags to options
|
||||||
|
registry.TransferFlags(cmd, options)
|
||||||
|
|
||||||
|
return &CommandTestHelper{
|
||||||
|
Cmd: cmd,
|
||||||
|
Registry: registry,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestApplyCmd creates an apply command for testing and returns a helper with its components
|
||||||
|
func TestApplyCmd() *CommandTestHelper {
|
||||||
|
// Create command components
|
||||||
|
optionsFactory := factory.NewApplyOptionsFactory()
|
||||||
|
options := optionsFactory.CreateOptions().(*config.ApplyOptions)
|
||||||
|
registry := optionsFactory.GetFlagRegistry()
|
||||||
|
|
||||||
|
// Create command manually
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "apply",
|
||||||
|
Short: "Apply all resources from state file only when there are changes",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register flags
|
||||||
|
registry.RegisterFlags(cmd)
|
||||||
|
|
||||||
|
return &CommandTestHelper{
|
||||||
|
Cmd: cmd,
|
||||||
|
Registry: registry,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTemplateCmd creates a template command for testing and returns a helper with its components
|
||||||
|
func TestTemplateCmd() *CommandTestHelper {
|
||||||
|
// Create command components
|
||||||
|
optionsFactory := factory.NewTemplateOptionsFactory()
|
||||||
|
options := optionsFactory.CreateOptions().(*config.TemplateOptions)
|
||||||
|
registry := optionsFactory.GetFlagRegistry()
|
||||||
|
|
||||||
|
// Create command manually
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "template",
|
||||||
|
Short: "Template releases defined in state file",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register flags
|
||||||
|
registry.RegisterFlags(cmd)
|
||||||
|
|
||||||
|
return &CommandTestHelper{
|
||||||
|
Cmd: cmd,
|
||||||
|
Registry: registry,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSyncCmd creates a sync command for testing and returns a helper with its components
|
||||||
|
func TestSyncCmd() *CommandTestHelper {
|
||||||
|
// Create command components
|
||||||
|
optionsFactory := factory.NewSyncOptionsFactory()
|
||||||
|
options := optionsFactory.CreateOptions().(*config.SyncOptions)
|
||||||
|
registry := optionsFactory.GetFlagRegistry()
|
||||||
|
|
||||||
|
// Create command manually
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "sync",
|
||||||
|
Short: "Sync all resources from state file",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register flags
|
||||||
|
registry.RegisterFlags(cmd)
|
||||||
|
|
||||||
|
return &CommandTestHelper{
|
||||||
|
Cmd: cmd,
|
||||||
|
Registry: registry,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
# Helmfile Test Utilities
|
||||||
|
|
||||||
|
This package provides testing utilities for the Helmfile project, making it easier to write unit tests for Helm-related functionality.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `testutil` package contains:
|
||||||
|
|
||||||
|
1. Mock implementations for Helm execution
|
||||||
|
2. Utility functions for testing
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### Mock Helm Executors
|
||||||
|
|
||||||
|
The package provides mock implementations of Helm executors that can be used in tests:
|
||||||
|
|
||||||
|
- `V3HelmExec`: A mock that can be configured to simulate Helm 3 behavior
|
||||||
|
- `VersionHelmExec`: A mock that can be configured with a specific Helm version
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Create a mock for Helm 3
|
||||||
|
helmExec := testutil.NewV3HelmExec(true)
|
||||||
|
|
||||||
|
// Create a mock for a specific Helm version
|
||||||
|
versionExec := testutil.NewVersionHelmExec("3.8.0")
|
||||||
|
```
|
||||||
|
|
||||||
|
These mocks implement the Helm executor interface but will panic if any unexpected methods are called, making them useful for strict testing scenarios.
|
||||||
|
|
||||||
|
### Utility Functions
|
||||||
|
|
||||||
|
#### CaptureStdout
|
||||||
|
|
||||||
|
Captures stdout output during the execution of a function:
|
||||||
|
|
||||||
|
```go
|
||||||
|
output, err := testutil.CaptureStdout(func() {
|
||||||
|
fmt.Println("Hello, world!")
|
||||||
|
})
|
||||||
|
// output will contain "Hello, world!\n"
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful for testing functions that write to stdout.
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Testing with V3HelmExec
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestMyFunction(t *testing.T) {
|
||||||
|
// Create a mock Helm executor configured as Helm 3
|
||||||
|
helmExec := testutil.NewV3HelmExec(true)
|
||||||
|
|
||||||
|
// Use in your test
|
||||||
|
result := myFunctionThatChecksHelmVersion(helmExec)
|
||||||
|
|
||||||
|
// Assert that the result is as expected for Helm 3
|
||||||
|
assert.True(t, result)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing with VersionHelmExec
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestVersionCompatibility(t *testing.T) {
|
||||||
|
// Create a mock with specific version
|
||||||
|
helmExec := testutil.NewVersionHelmExec("3.7.1")
|
||||||
|
|
||||||
|
// Test version comparison
|
||||||
|
assert.True(t, helmExec.IsVersionAtLeast("3.7.0"))
|
||||||
|
assert.False(t, helmExec.IsVersionAtLeast("3.8.0"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Capturing Output
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestOutputFunction(t *testing.T) {
|
||||||
|
output, err := testutil.CaptureStdout(func() {
|
||||||
|
MyFunctionThatPrintsOutput()
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, output, "Expected output")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
When adding new test utilities, please ensure they are well-documented and include appropriate tests.
|
||||||
Loading…
Reference in New Issue