290 lines
8.4 KiB
Go
290 lines
8.4 KiB
Go
package state
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/helmfile/helmfile/pkg/environment"
|
|
"github.com/helmfile/helmfile/pkg/filesystem"
|
|
)
|
|
|
|
// TestProcessChartificationKubeContext tests that --kube-context flag is properly
|
|
// added to chartifyOpts.TemplateArgs when using jsonPatches with cluster-requiring commands.
|
|
// This is a regression test for the issue where helm template does not receive
|
|
// --kube-context arg when using kustomize (jsonPatches).
|
|
func TestProcessChartificationKubeContext(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
helmfileCommand string
|
|
kubeContext string
|
|
envKubeContext string
|
|
helmDefaults string
|
|
expectContext bool
|
|
expectDryRun bool
|
|
}{
|
|
{
|
|
name: "diff command with helmDefaults kubeContext",
|
|
helmfileCommand: "diff",
|
|
helmDefaults: "minikube",
|
|
expectContext: true,
|
|
expectDryRun: true,
|
|
},
|
|
{
|
|
name: "apply command with release kubeContext",
|
|
helmfileCommand: "apply",
|
|
kubeContext: "prod-cluster",
|
|
expectContext: true,
|
|
expectDryRun: true,
|
|
},
|
|
{
|
|
name: "sync command with env kubeContext",
|
|
helmfileCommand: "sync",
|
|
envKubeContext: "staging-cluster",
|
|
expectContext: true,
|
|
expectDryRun: true,
|
|
},
|
|
{
|
|
name: "template command should not add cluster flags",
|
|
helmfileCommand: "template",
|
|
helmDefaults: "minikube",
|
|
expectContext: false,
|
|
expectDryRun: false,
|
|
},
|
|
{
|
|
name: "build command should not add cluster flags",
|
|
helmfileCommand: "build",
|
|
helmDefaults: "minikube",
|
|
expectContext: false,
|
|
expectDryRun: false,
|
|
},
|
|
{
|
|
name: "diff command without kubeContext",
|
|
helmfileCommand: "diff",
|
|
expectContext: false,
|
|
expectDryRun: true,
|
|
},
|
|
{
|
|
name: "destroy command with kubeContext",
|
|
helmfileCommand: "destroy",
|
|
helmDefaults: "test-cluster",
|
|
expectContext: true,
|
|
expectDryRun: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create a release with jsonPatches to trigger chartification
|
|
release := &ReleaseSpec{
|
|
Name: "test-release",
|
|
Namespace: "default",
|
|
Chart: "./test-chart",
|
|
JSONPatches: []interface{}{
|
|
map[string]interface{}{
|
|
"target": map[string]interface{}{
|
|
"group": "apps",
|
|
"version": "v1",
|
|
"kind": "Deployment",
|
|
"name": "test",
|
|
},
|
|
"patch": []interface{}{
|
|
map[string]interface{}{
|
|
"op": "add",
|
|
"path": "/spec/template/spec/containers/0/args/-",
|
|
"value": "test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Set kubeContext on release if provided
|
|
if tt.kubeContext != "" {
|
|
release.KubeContext = tt.kubeContext
|
|
}
|
|
|
|
// Create HelmState
|
|
state := &HelmState{
|
|
basePath: "/tmp/test",
|
|
fs: filesystem.FromFileSystem(filesystem.FileSystem{
|
|
DirectoryExistsAt: func(path string) bool {
|
|
return strings.Contains(path, "test-chart")
|
|
},
|
|
FileExistsAt: func(path string) bool {
|
|
return false
|
|
},
|
|
DeleteFile: func(path string) error {
|
|
return nil
|
|
},
|
|
Glob: func(pattern string) ([]string, error) {
|
|
return nil, nil
|
|
},
|
|
}),
|
|
logger: logger,
|
|
valsRuntime: valsRuntime,
|
|
RenderedValues: map[string]any{},
|
|
ReleaseSetSpec: ReleaseSetSpec{
|
|
Env: environment.Environment{
|
|
Name: "default",
|
|
},
|
|
Environments: map[string]EnvironmentSpec{
|
|
"default": {
|
|
KubeContext: tt.envKubeContext,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Set helmDefaults kubeContext if provided
|
|
if tt.helmDefaults != "" {
|
|
state.ReleaseSetSpec.HelmDefaults.KubeContext = tt.helmDefaults
|
|
}
|
|
|
|
// Prepare chartify (this generates the Chartify object with jsonPatches)
|
|
chartification, clean, err := state.PrepareChartify(nil, release, "./test-chart", 0)
|
|
require.NoError(t, err)
|
|
defer clean()
|
|
|
|
// Ensure chartification is needed (jsonPatches should trigger it)
|
|
require.NotNil(t, chartification, "Chartification should be needed when jsonPatches are present")
|
|
|
|
// Process chartification with the test command
|
|
opts := ChartPrepareOptions{}
|
|
_, _, err = state.processChartification(chartification, release, "./test-chart", opts, false, tt.helmfileCommand)
|
|
|
|
// We expect an error because we don't have an actual chart, but we can still
|
|
// check that TemplateArgs was set correctly
|
|
// The error will come from chartify.Chartify, not from our logic
|
|
// So let's check the chartification.Opts.TemplateArgs directly
|
|
|
|
if tt.expectContext {
|
|
// Determine which kubeContext should be used
|
|
expectedContext := tt.kubeContext
|
|
if expectedContext == "" {
|
|
expectedContext = tt.envKubeContext
|
|
}
|
|
if expectedContext == "" {
|
|
expectedContext = tt.helmDefaults
|
|
}
|
|
|
|
assert.Contains(t, chartification.Opts.TemplateArgs, "--kube-context",
|
|
"TemplateArgs should contain --kube-context flag")
|
|
assert.Contains(t, chartification.Opts.TemplateArgs, expectedContext,
|
|
"TemplateArgs should contain the expected kube context: %s", expectedContext)
|
|
} else if tt.helmDefaults != "" || tt.kubeContext != "" || tt.envKubeContext != "" {
|
|
// If a context is configured but not expected (offline commands)
|
|
assert.NotContains(t, chartification.Opts.TemplateArgs, "--kube-context",
|
|
"TemplateArgs should not contain --kube-context flag for offline commands")
|
|
}
|
|
|
|
if tt.expectDryRun {
|
|
assert.Contains(t, chartification.Opts.TemplateArgs, "--dry-run=server",
|
|
"TemplateArgs should contain --dry-run=server flag")
|
|
} else {
|
|
assert.NotContains(t, chartification.Opts.TemplateArgs, "--dry-run",
|
|
"TemplateArgs should not contain --dry-run flag for offline commands")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestProcessChartificationKubeContextPriority tests the priority order
|
|
// for kube context selection: release.KubeContext > env.KubeContext > helmDefaults.KubeContext
|
|
func TestProcessChartificationKubeContextPriority(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
releaseContext string
|
|
envContext string
|
|
helmDefaultsContext string
|
|
expectedContext string
|
|
}{
|
|
{
|
|
name: "release context takes priority",
|
|
releaseContext: "release-ctx",
|
|
envContext: "env-ctx",
|
|
helmDefaultsContext: "defaults-ctx",
|
|
expectedContext: "release-ctx",
|
|
},
|
|
{
|
|
name: "env context when release not set",
|
|
envContext: "env-ctx",
|
|
helmDefaultsContext: "defaults-ctx",
|
|
expectedContext: "env-ctx",
|
|
},
|
|
{
|
|
name: "helmDefaults context when others not set",
|
|
helmDefaultsContext: "defaults-ctx",
|
|
expectedContext: "defaults-ctx",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
release := &ReleaseSpec{
|
|
Name: "test-release",
|
|
Namespace: "default",
|
|
Chart: "./test-chart",
|
|
JSONPatches: []interface{}{
|
|
map[string]interface{}{
|
|
"target": map[string]interface{}{
|
|
"kind": "Deployment",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if tt.releaseContext != "" {
|
|
release.KubeContext = tt.releaseContext
|
|
}
|
|
|
|
state := &HelmState{
|
|
basePath: "/tmp/test",
|
|
fs: filesystem.FromFileSystem(filesystem.FileSystem{
|
|
DirectoryExistsAt: func(path string) bool {
|
|
return strings.Contains(path, "test-chart")
|
|
},
|
|
FileExistsAt: func(path string) bool {
|
|
return false
|
|
},
|
|
DeleteFile: func(path string) error {
|
|
return nil
|
|
},
|
|
Glob: func(pattern string) ([]string, error) {
|
|
return nil, nil
|
|
},
|
|
}),
|
|
logger: logger,
|
|
valsRuntime: valsRuntime,
|
|
RenderedValues: map[string]any{},
|
|
ReleaseSetSpec: ReleaseSetSpec{
|
|
Env: environment.Environment{
|
|
Name: "default",
|
|
},
|
|
Environments: map[string]EnvironmentSpec{
|
|
"default": {
|
|
KubeContext: tt.envContext,
|
|
},
|
|
},
|
|
HelmDefaults: HelmSpec{
|
|
KubeContext: tt.helmDefaultsContext,
|
|
},
|
|
},
|
|
}
|
|
|
|
chartification, clean, err := state.PrepareChartify(nil, release, "./test-chart", 0)
|
|
require.NoError(t, err)
|
|
defer clean()
|
|
require.NotNil(t, chartification)
|
|
|
|
opts := ChartPrepareOptions{}
|
|
_, _, _ = state.processChartification(chartification, release, "./test-chart", opts, false, "diff")
|
|
|
|
assert.Contains(t, chartification.Opts.TemplateArgs, tt.expectedContext,
|
|
"TemplateArgs should contain the expected context: %s", tt.expectedContext)
|
|
})
|
|
}
|
|
}
|