helmfile/pkg/state/issue_2296_test.go

197 lines
6.9 KiB
Go

package state
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Note: boolPtr helper is already defined in skip_test.go and shared across test files in this package.
// TestHelmDefaultsSkipDepsAndSkipRefreshIntegration tests that helmDefaults.skipDeps
// and helmDefaults.skipRefresh are properly respected when preparing charts.
// This is a regression test for issue #2296.
//
// This test verifies the skipDeps/skipRefresh calculation in state.go that affects:
// 1. buildDeps - whether to run `helm dep build` for local charts
// 2. skipRefresh - whether to skip chart refresh operations
//
// Note: The skipRepos logic in pkg/app/run.go uses both helmDefaults.skipDeps and
// helmDefaults.skipRefresh to determine whether to sync repos. Both flags cause
// repo sync to be skipped because:
// - skipRefresh explicitly means "don't update repos"
// - skipDeps implies "I have all dependencies locally" which means repo data isn't needed
// The skipRepos behavior is documented in run.go comments and tested via integration tests.
func TestHelmDefaultsSkipDepsAndSkipRefreshIntegration(t *testing.T) {
// Create a temporary directory with a local chart
tempDir := t.TempDir()
chartDir := filepath.Join(tempDir, "chart")
require.NoError(t, os.MkdirAll(chartDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(chartDir, "Chart.yaml"), []byte(`
apiVersion: v2
name: test-chart
version: 0.1.0
`), 0644))
tests := []struct {
name string
helmDefaultsSkipDeps bool
helmDefaultsSkipRefresh bool
releaseSkipDeps *bool
releaseSkipRefresh *bool
optsSkipDeps bool
optsSkipRefresh bool
chartPath string
isLocal bool
expectedBuildDeps bool // buildDeps = !skipDeps for local charts
expectedSkipRefresh bool
}{
{
name: "helmDefaults.skipDeps=true should result in buildDeps=false",
helmDefaultsSkipDeps: true,
helmDefaultsSkipRefresh: false,
chartPath: "./chart",
isLocal: true,
expectedBuildDeps: false, // skipDeps=true means buildDeps=false
expectedSkipRefresh: false,
},
{
name: "helmDefaults.skipRefresh=true should result in skipRefresh=true",
helmDefaultsSkipDeps: false,
helmDefaultsSkipRefresh: true,
chartPath: "./chart",
isLocal: true,
expectedBuildDeps: true, // skipDeps=false means buildDeps=true
expectedSkipRefresh: true,
},
{
name: "both helmDefaults set should affect both flags",
helmDefaultsSkipDeps: true,
helmDefaultsSkipRefresh: true,
chartPath: "./chart",
isLocal: true,
expectedBuildDeps: false,
expectedSkipRefresh: true,
},
{
name: "release-level skipDeps overrides helmDefaults",
helmDefaultsSkipDeps: false,
helmDefaultsSkipRefresh: false,
releaseSkipDeps: boolPtr(true),
chartPath: "./chart",
isLocal: true,
expectedBuildDeps: false, // release-level skipDeps=true
expectedSkipRefresh: false,
},
{
name: "CLI opts skipDeps has priority",
helmDefaultsSkipDeps: false,
helmDefaultsSkipRefresh: false,
optsSkipDeps: true,
chartPath: "./chart",
isLocal: true,
expectedBuildDeps: false, // opts skipDeps=true
expectedSkipRefresh: false,
},
{
name: "non-local chart always has buildDeps=false",
helmDefaultsSkipDeps: false,
helmDefaultsSkipRefresh: false,
chartPath: "stable/nginx",
isLocal: false,
expectedBuildDeps: false, // non-local charts don't build deps
expectedSkipRefresh: true, // non-local charts skip refresh
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Calculate skipDeps using the actual logic from state.go
skipDepsGlobal := tt.optsSkipDeps
skipDepsRelease := tt.releaseSkipDeps != nil && *tt.releaseSkipDeps
skipDepsDefault := tt.releaseSkipDeps == nil && tt.helmDefaultsSkipDeps
chartFetchedByGoGetter := false
skipDeps := (!tt.isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault
// Calculate skipRefresh using the actual logic from state.go
skipRefreshGlobal := tt.optsSkipRefresh
skipRefreshRelease := tt.releaseSkipRefresh != nil && *tt.releaseSkipRefresh
skipRefreshDefault := tt.releaseSkipRefresh == nil && tt.helmDefaultsSkipRefresh
skipRefresh := !tt.isLocal || skipRefreshGlobal || skipRefreshRelease || skipRefreshDefault
// buildDeps = !skipDeps (for local charts processed normally)
buildDeps := !skipDeps
assert.Equal(t, tt.expectedBuildDeps, buildDeps,
"buildDeps mismatch: expected %v, got %v (skipDeps=%v)", tt.expectedBuildDeps, buildDeps, skipDeps)
assert.Equal(t, tt.expectedSkipRefresh, skipRefresh,
"skipRefresh mismatch: expected %v, got %v", tt.expectedSkipRefresh, skipRefresh)
})
}
}
// TestSkipReposLogic tests the skipRepos calculation used in pkg/app/run.go.
// This documents and verifies the expected behavior: both helmDefaults.skipDeps
// and helmDefaults.skipRefresh should cause repo sync to be skipped.
//
// The actual skipRepos logic is in run.go:
//
// skipRepos := opts.SkipRepos || r.state.HelmDefaults.SkipDeps || r.state.HelmDefaults.SkipRefresh
func TestSkipReposLogic(t *testing.T) {
tests := []struct {
name string
optsSkipRepos bool
skipDeps bool
skipRefresh bool
expectedSkipRepo bool
}{
{
name: "all false - repos should sync",
optsSkipRepos: false,
skipDeps: false,
skipRefresh: false,
expectedSkipRepo: false,
},
{
name: "opts.SkipRepos=true - repos should be skipped",
optsSkipRepos: true,
skipDeps: false,
skipRefresh: false,
expectedSkipRepo: true,
},
{
name: "helmDefaults.skipDeps=true - repos should be skipped",
optsSkipRepos: false,
skipDeps: true,
skipRefresh: false,
expectedSkipRepo: true,
},
{
name: "helmDefaults.skipRefresh=true - repos should be skipped",
optsSkipRepos: false,
skipDeps: false,
skipRefresh: true,
expectedSkipRepo: true,
},
{
name: "both helmDefaults set - repos should be skipped",
optsSkipRepos: false,
skipDeps: true,
skipRefresh: true,
expectedSkipRepo: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// This mirrors the logic in pkg/app/run.go withPreparedCharts and Deps
skipRepos := tt.optsSkipRepos || tt.skipDeps || tt.skipRefresh
assert.Equal(t, tt.expectedSkipRepo, skipRepos,
"skipRepos mismatch: expected %v, got %v", tt.expectedSkipRepo, skipRepos)
})
}
}