From ed76a36ab9b4c8f5a56049aa201dd8ce04836ecb Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 15:37:08 +1200 Subject: [PATCH 001/161] refactor(cmd/helm): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- cmd/helm/helm_test.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index a9362f772..05d05dece 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -18,13 +18,13 @@ package main import ( "bytes" - "errors" "os" "os/exec" "runtime" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCliPluginExitCode(t *testing.T) { @@ -62,20 +62,13 @@ func TestCliPluginExitCode(t *testing.T) { err := cmd.Run() exiterr := &exec.ExitError{} - ok := errors.As(err, &exiterr) - if !ok { - t.Fatalf("Unexpected error type returned by os.Exit: %T", err) - } + require.ErrorAs(t, err, &exiterr) assert.Empty(t, stdout.String()) expectedStderr := "level=WARN msg=\"failed to load plugin (ignoring)\" plugin_yaml=../../pkg/cmd/testdata/helmhome/helm/plugins/noversion/plugin.yaml error=\"failed to load plugin \\\"../../pkg/cmd/testdata/helmhome/helm/plugins/noversion\\\": plugin `version` is required\"\nError: plugin \"exitwith\" exited with error\n" - if stderr.String() != expectedStderr { - t.Errorf("Expected %q written to stderr: Got %q", expectedStderr, stderr.String()) - } + assert.Equal(t, expectedStderr, stderr.String()) - if exiterr.ExitCode() != 43 { - t.Errorf("Expected exit code 43: Got %d", exiterr.ExitCode()) - } + assert.Equal(t, 43, exiterr.ExitCode()) } } From f4d713abb210230b3935c4a9685f1f34a8330970 Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 16:17:14 +1200 Subject: [PATCH 002/161] refactor(pkg): convert tests to testify assert/require Convert pkg/gates, pkg/kubeenv, pkg/ignore, and pkg/helmpath test files from native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) to github.com/stretchr/testify equivalents (assert.X, require.X). Signed-off-by: George Jenkins --- pkg/gates/gates_test.go | 18 ++++------ pkg/helmpath/home_unix_test.go | 20 ++++------- pkg/helmpath/home_windows_test.go | 15 ++++---- pkg/helmpath/lazypath_darwin_test.go | 25 ++++--------- pkg/helmpath/lazypath_unix_test.go | 25 ++++--------- pkg/helmpath/lazypath_windows_test.go | 25 ++++--------- pkg/ignore/rules_test.go | 52 +++++++++------------------ 7 files changed, 56 insertions(+), 124 deletions(-) diff --git a/pkg/gates/gates_test.go b/pkg/gates/gates_test.go index 4d77199e6..217ee1bbe 100644 --- a/pkg/gates/gates_test.go +++ b/pkg/gates/gates_test.go @@ -18,6 +18,8 @@ package gates import ( "os" "testing" + + "github.com/stretchr/testify/assert" ) const name string = "HELM_EXPERIMENTAL_FEATURE" @@ -25,31 +27,23 @@ const name string = "HELM_EXPERIMENTAL_FEATURE" func TestIsEnabled(t *testing.T) { g := Gate(name) - if g.IsEnabled() { - t.Errorf("feature gate shows as available, but the environment variable %s was not set", name) - } + assert.False(t, g.IsEnabled(), "feature gate shows as available, but the environment variable %s was not set", name) t.Setenv(name, "1") - if !g.IsEnabled() { - t.Errorf("feature gate shows as disabled, but the environment variable %s was set", name) - } + assert.True(t, g.IsEnabled(), "feature gate shows as disabled, but the environment variable %s was set", name) } func TestError(t *testing.T) { os.Unsetenv(name) g := Gate(name) - if g.Error().Error() != "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature" { - t.Errorf("incorrect error message. Received %s", g.Error().Error()) - } + assert.Equal(t, "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature", g.Error().Error()) } func TestString(t *testing.T) { os.Unsetenv(name) g := Gate(name) - if g.String() != "HELM_EXPERIMENTAL_FEATURE" { - t.Errorf("incorrect string representation. Received %s", g.String()) - } + assert.Equal(t, "HELM_EXPERIMENTAL_FEATURE", g.String()) } diff --git a/pkg/helmpath/home_unix_test.go b/pkg/helmpath/home_unix_test.go index a64c9bcd6..84c912502 100644 --- a/pkg/helmpath/home_unix_test.go +++ b/pkg/helmpath/home_unix_test.go @@ -16,9 +16,10 @@ package helmpath import ( - "runtime" "testing" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/pkg/helmpath/xdg" ) @@ -26,20 +27,13 @@ func TestHelmHome(t *testing.T) { t.Setenv(xdg.CacheHomeEnvVar, "/cache") t.Setenv(xdg.ConfigHomeEnvVar, "/config") t.Setenv(xdg.DataHomeEnvVar, "/data") - isEq := func(t *testing.T, got, expected string) { - t.Helper() - if expected != got { - t.Error(runtime.GOOS) - t.Errorf("Expected %q, got %q", expected, got) - } - } - - isEq(t, CachePath(), "/cache/helm") - isEq(t, ConfigPath(), "/config/helm") - isEq(t, DataPath(), "/data/helm") + + assert.Equal(t, "/cache/helm", CachePath()) + assert.Equal(t, "/config/helm", ConfigPath()) + assert.Equal(t, "/data/helm", DataPath()) // test to see if lazy-loading environment variables at runtime works t.Setenv(xdg.CacheHomeEnvVar, "/cache2") - isEq(t, CachePath(), "/cache2/helm") + assert.Equal(t, "/cache2/helm", CachePath()) } diff --git a/pkg/helmpath/home_windows_test.go b/pkg/helmpath/home_windows_test.go index 38fe5e4f1..4c2c7d11a 100644 --- a/pkg/helmpath/home_windows_test.go +++ b/pkg/helmpath/home_windows_test.go @@ -19,6 +19,8 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/pkg/helmpath/xdg" ) @@ -26,18 +28,13 @@ func TestHelmHome(t *testing.T) { os.Setenv(xdg.CacheHomeEnvVar, "c:\\") os.Setenv(xdg.ConfigHomeEnvVar, "d:\\") os.Setenv(xdg.DataHomeEnvVar, "e:\\") - isEq := func(t *testing.T, a, b string) { - if a != b { - t.Errorf("Expected %q, got %q", b, a) - } - } - isEq(t, CachePath(), "c:\\helm") - isEq(t, ConfigPath(), "d:\\helm") - isEq(t, DataPath(), "e:\\helm") + assert.Equal(t, "c:\\helm", CachePath()) + assert.Equal(t, "d:\\helm", ConfigPath()) + assert.Equal(t, "e:\\helm", DataPath()) // test to see if lazy-loading environment variables at runtime works os.Setenv(xdg.CacheHomeEnvVar, "f:\\") - isEq(t, CachePath(), "f:\\helm") + assert.Equal(t, "f:\\helm", CachePath()) } diff --git a/pkg/helmpath/lazypath_darwin_test.go b/pkg/helmpath/lazypath_darwin_test.go index e3006d0d5..143750f04 100644 --- a/pkg/helmpath/lazypath_darwin_test.go +++ b/pkg/helmpath/lazypath_darwin_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" "k8s.io/client-go/util/homedir" "helm.sh/helm/v4/pkg/helmpath/xdg" @@ -36,17 +37,13 @@ func TestDataPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "Library", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) t.Setenv(xdg.DataHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) } func TestConfigPath(t *testing.T) { @@ -54,17 +51,13 @@ func TestConfigPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "Library", "Preferences", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) t.Setenv(xdg.ConfigHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) } func TestCachePath(t *testing.T) { @@ -72,15 +65,11 @@ func TestCachePath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "Library", "Caches", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) t.Setenv(xdg.CacheHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) } diff --git a/pkg/helmpath/lazypath_unix_test.go b/pkg/helmpath/lazypath_unix_test.go index 4b0f2429b..6f8c6c2e8 100644 --- a/pkg/helmpath/lazypath_unix_test.go +++ b/pkg/helmpath/lazypath_unix_test.go @@ -19,6 +19,7 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" "k8s.io/client-go/util/homedir" "helm.sh/helm/v4/pkg/helmpath/xdg" @@ -33,47 +34,35 @@ const ( func TestDataPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), ".local", "share", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) t.Setenv(xdg.DataHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) } func TestConfigPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), ".config", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) t.Setenv(xdg.ConfigHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) } func TestCachePath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), ".cache", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) t.Setenv(xdg.CacheHomeEnvVar, "/tmp") expected = filepath.Join("/tmp", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) } diff --git a/pkg/helmpath/lazypath_windows_test.go b/pkg/helmpath/lazypath_windows_test.go index ebd95e812..df8ad2d80 100644 --- a/pkg/helmpath/lazypath_windows_test.go +++ b/pkg/helmpath/lazypath_windows_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" "k8s.io/client-go/util/homedir" "helm.sh/helm/v4/pkg/helmpath/xdg" @@ -37,17 +38,13 @@ func TestDataPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) os.Setenv(xdg.DataHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) expected = filepath.Join(homedir.HomeDir(), "xdg", appName, testFile) - if lazy.dataPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile)) - } + assert.Equal(t, expected, lazy.dataPath(testFile)) } func TestConfigPath(t *testing.T) { @@ -56,17 +53,13 @@ func TestConfigPath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) os.Setenv(xdg.ConfigHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) expected = filepath.Join(homedir.HomeDir(), "xdg", appName, testFile) - if lazy.configPath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile)) - } + assert.Equal(t, expected, lazy.configPath(testFile)) } func TestCachePath(t *testing.T) { @@ -75,15 +68,11 @@ func TestCachePath(t *testing.T) { expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) os.Setenv(xdg.CacheHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")) expected = filepath.Join(homedir.HomeDir(), "xdg", appName, testFile) - if lazy.cachePath(testFile) != expected { - t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile)) - } + assert.Equal(t, expected, lazy.cachePath(testFile)) } diff --git a/pkg/ignore/rules_test.go b/pkg/ignore/rules_test.go index 9581cf09f..02ba63588 100644 --- a/pkg/ignore/rules_test.go +++ b/pkg/ignore/rules_test.go @@ -21,6 +21,9 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var testdata = "./testdata" @@ -36,22 +39,14 @@ baz/bar/foo.txt one/more ` r, err := parseString(rules) - if err != nil { - t.Fatalf("Error parsing rules: %s", err) - } + require.NoError(t, err, "Error parsing rules") - if len(r.patterns) != 4 { - t.Errorf("Expected 4 rules, got %d", len(r.patterns)) - } + assert.Len(t, r.patterns, 4) expects := []string{"foo", "bar/*", "baz/bar/foo.txt", "one/more"} for i, p := range r.patterns { - if p.raw != expects[i] { - t.Errorf("Expected %q, got %q", expects[i], p.raw) - } - if p.match == nil { - t.Errorf("Expected %s to have a matcher function.", p.raw) - } + assert.Equal(t, expects[i], p.raw) + assert.NotNil(t, p.match, "Expected %s to have a matcher function.", p.raw) } } @@ -59,26 +54,19 @@ func TestParseFail(t *testing.T) { shouldFail := []string{"foo/**/bar", "[z-"} for _, fail := range shouldFail { _, err := parseString(fail) - if err == nil { - t.Errorf("Rule %q should have failed", fail) - } + assert.Error(t, err, "Rule %q should have failed", fail) } } func TestParseFile(t *testing.T) { f := filepath.Join(testdata, HelmIgnore) - if _, err := os.Stat(f); err != nil { - t.Fatalf("Fixture %s missing: %s", f, err) - } + _, err := os.Stat(f) + require.NoError(t, err, "Fixture %s missing", f) r, err := ParseFile(f) - if err != nil { - t.Fatalf("Failed to parse rules file: %s", err) - } + require.NoError(t, err, "Failed to parse rules file") - if len(r.patterns) != 3 { - t.Errorf("Expected 3 patterns, got %d", len(r.patterns)) - } + assert.Len(t, r.patterns, 3) } func TestIgnore(t *testing.T) { @@ -126,17 +114,11 @@ func TestIgnore(t *testing.T) { for _, test := range tests { r, err := parseString(test.pattern) - if err != nil { - t.Fatalf("Failed to parse: %s", err) - } + require.NoError(t, err, "Failed to parse: %s", test.pattern) fi, err := os.Stat(filepath.Join(testdata, test.name)) - if err != nil { - t.Fatalf("Fixture missing: %s", err) - } + require.NoError(t, err, "Fixture missing: %s", test.name) - if r.Ignore(test.name, fi) != test.expect { - t.Errorf("Expected %q to be %v for pattern %q", test.name, test.expect, test.pattern) - } + assert.Equal(t, test.expect, r.Ignore(test.name, fi), "Expected %q to be %v for pattern %q", test.name, test.expect, test.pattern) } } @@ -144,9 +126,7 @@ func TestAddDefaults(t *testing.T) { r := Rules{} r.AddDefaults() - if len(r.patterns) != 1 { - t.Errorf("Expected 1 default patterns, got %d", len(r.patterns)) - } + assert.Len(t, r.patterns, 1) } func parseString(str string) (*Rules, error) { From 9ad5620edc1b51507d111f7f998cc0f5b95e5726 Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 12:16:54 -0700 Subject: [PATCH 003/161] Update pkg/ignore/rules_test.go Co-authored-by: Terry Howe Signed-off-by: George Jenkins --- pkg/ignore/rules_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ignore/rules_test.go b/pkg/ignore/rules_test.go index 02ba63588..30e157a52 100644 --- a/pkg/ignore/rules_test.go +++ b/pkg/ignore/rules_test.go @@ -41,7 +41,7 @@ one/more r, err := parseString(rules) require.NoError(t, err, "Error parsing rules") - assert.Len(t, r.patterns, 4) + require.Len(t, r.patterns, 4) expects := []string{"foo", "bar/*", "baz/bar/foo.txt", "one/more"} for i, p := range r.patterns { From 16b0760dfd99b5c501cbfc2138a207e1b3512c0f Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 17 Jun 2026 21:28:58 +1200 Subject: [PATCH 004/161] refactor(pkg/cli): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- pkg/cli/environment_test.go | 62 ++++++++++------------------------ pkg/cli/values/options_test.go | 61 +++++++++++---------------------- 2 files changed, 37 insertions(+), 86 deletions(-) diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index 52326eeff..f1067f6c6 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -23,6 +23,8 @@ import ( "testing" "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/version" ) @@ -30,14 +32,10 @@ import ( func TestSetNamespace(t *testing.T) { settings := New() - if settings.namespace != "" { - t.Errorf("Expected empty namespace, got %s", settings.namespace) - } + assert.Empty(t, settings.namespace) settings.SetNamespace("testns") - if settings.namespace != "testns" { - t.Errorf("Expected namespace testns, got %s", settings.namespace) - } + assert.Equal(t, "testns", settings.namespace) } func TestEnvSettings(t *testing.T) { @@ -134,36 +132,16 @@ func TestEnvSettings(t *testing.T) { settings.AddFlags(flags) flags.Parse(strings.Split(tt.args, " ")) - if settings.Debug != tt.debug { - t.Errorf("expected debug %t, got %t", tt.debug, settings.Debug) - } - if settings.Namespace() != tt.ns { - t.Errorf("expected namespace %q, got %q", tt.ns, settings.Namespace()) - } - if settings.KubeContext != tt.kcontext { - t.Errorf("expected kube-context %q, got %q", tt.kcontext, settings.KubeContext) - } - if settings.MaxHistory != tt.maxhistory { - t.Errorf("expected maxHistory %d, got %d", tt.maxhistory, settings.MaxHistory) - } - if tt.kubeAsUser != settings.KubeAsUser { - t.Errorf("expected kAsUser %q, got %q", tt.kubeAsUser, settings.KubeAsUser) - } - if !reflect.DeepEqual(tt.kubeAsGroups, settings.KubeAsGroups) { - t.Errorf("expected kAsGroups %+v, got %+v", len(tt.kubeAsGroups), len(settings.KubeAsGroups)) - } - if tt.kubeCaFile != settings.KubeCaFile { - t.Errorf("expected kCaFile %q, got %q", tt.kubeCaFile, settings.KubeCaFile) - } - if tt.burstLimit != settings.BurstLimit { - t.Errorf("expected BurstLimit %d, got %d", tt.burstLimit, settings.BurstLimit) - } - if tt.kubeInsecure != settings.KubeInsecureSkipTLSVerify { - t.Errorf("expected kubeInsecure %t, got %t", tt.kubeInsecure, settings.KubeInsecureSkipTLSVerify) - } - if tt.kubeTLSServer != settings.KubeTLSServerName { - t.Errorf("expected kubeTLSServer %q, got %q", tt.kubeTLSServer, settings.KubeTLSServerName) - } + assert.Equal(t, tt.debug, settings.Debug, "debug") + assert.Equal(t, tt.ns, settings.Namespace(), "namespace") + assert.Equal(t, tt.kcontext, settings.KubeContext, "kube-context") + assert.Equal(t, tt.maxhistory, settings.MaxHistory, "maxHistory") + assert.Equal(t, tt.kubeAsUser, settings.KubeAsUser, "kubeAsUser") + assert.True(t, reflect.DeepEqual(tt.kubeAsGroups, settings.KubeAsGroups), "kubeAsGroups") + assert.Equal(t, tt.kubeCaFile, settings.KubeCaFile, "kubeCaFile") + assert.Equal(t, tt.burstLimit, settings.BurstLimit, "burstLimit") + assert.Equal(t, tt.kubeInsecure, settings.KubeInsecureSkipTLSVerify, "kubeInsecure") + assert.Equal(t, tt.kubeTLSServer, settings.KubeTLSServerName, "kubeTLSServer") }) } } @@ -235,9 +213,7 @@ func TestEnvOrBool(t *testing.T) { t.Setenv(tt.env, tt.val) } actual := envBoolOr(tt.env, tt.def) - if actual != tt.expected { - t.Errorf("expected result %t, got %t", tt.expected, actual) - } + assert.Equal(t, tt.expected, actual) }) } } @@ -247,14 +223,10 @@ func TestUserAgentHeaderInK8sRESTClientConfig(t *testing.T) { settings := New() restConfig, err := settings.RESTClientGetter().ToRESTConfig() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectedUserAgent := version.GetUserAgent() - if restConfig.UserAgent != expectedUserAgent { - t.Errorf("expected User-Agent header %q in K8s REST client config, got %q", expectedUserAgent, restConfig.UserAgent) - } + assert.Equal(t, expectedUserAgent, restConfig.UserAgent) } func resetEnv() func() { diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index 571622d80..3a33da7f1 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -22,9 +22,11 @@ import ( "os" "path/filepath" "reflect" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/getter" ) @@ -90,10 +92,7 @@ func TestReadFile(t *testing.T) { tmpDir := t.TempDir() filePath := filepath.Join(tmpDir, "test.txt") content := []byte("local file content") - err := os.WriteFile(filePath, content, 0644) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filePath, content, 0644)) return filePath, func() {} // cleanup handled by t.TempDir() }, expectError: false, @@ -154,10 +153,7 @@ func TestReadFile(t *testing.T) { fileName := "ftp_file.txt" // Valid filename for filesystem filePath := filepath.Join(tmpDir, fileName) content := []byte("local fallback content") - err := os.WriteFile(filePath, content, 0644) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filePath, content, 0644)) return filePath, func() {} }, expectError: false, @@ -202,9 +198,7 @@ func TestReadFile(t *testing.T) { // Create a pipe for stdin r, w, err := os.Pipe() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer r.Close() defer w.Close() @@ -220,28 +214,21 @@ func TestReadFile(t *testing.T) { // Test the function got, err := readFile(actualFilePath, tt.providers) - if err != nil { - t.Errorf("readFile() error = %v, expected no error for stdin", err) - return - } - - if !bytes.Equal(got, testData) { - t.Errorf("readFile() = %v, want %v", got, testData) - } + assert.NoError(t, err, "readFile() expected no error for stdin") + assert.Equal(t, testData, got) return } // Regular test cases got, err := readFile(actualFilePath, tt.providers) - if (err != nil) != tt.expectError { - t.Errorf("readFile() error = %v, expectError %v", err, tt.expectError) + if tt.expectError { + assert.Error(t, err) return } + assert.NoError(t, err) - if !tt.expectError && tt.expectedData != nil { - if !bytes.Equal(got, tt.expectedData) { - t.Errorf("readFile() = %v, want %v", got, tt.expectedData) - } + if tt.expectedData != nil { + assert.Equal(t, tt.expectedData, got) } }) } @@ -272,13 +259,8 @@ func TestReadFileErrorMessages(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := readFile(tt.filePath, tt.providers) - if err == nil { - t.Errorf("readFile() expected error containing %q, got nil", tt.wantErr) - return - } - if !strings.Contains(err.Error(), tt.wantErr) { - t.Errorf("readFile() error = %v, want error containing %q", err, tt.wantErr) - } + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) }) } } @@ -288,9 +270,7 @@ func TestReadFileOriginal(t *testing.T) { var p getter.Providers filePath := "%a.txt" _, err := readFile(filePath, p) - if err == nil { - t.Error("Expected error when has special strings") - } + assert.Error(t, err, "Expected error when has special strings") } func TestMergeValuesCLI(t *testing.T) { @@ -376,13 +356,12 @@ func TestMergeValuesCLI(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := tt.opts.MergeValues(getter.Providers{}) - if (err != nil) != tt.wantErr { - t.Errorf("MergeValues() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + assert.Error(t, err) return } - if !tt.wantErr && !reflect.DeepEqual(got, tt.expected) { - t.Errorf("MergeValues() = %v, want %v", got, tt.expected) - } + assert.NoError(t, err) + assert.True(t, reflect.DeepEqual(got, tt.expected), "MergeValues() = %v, want %v", got, tt.expected) }) } } From daa045d4923007c1ab815b39038b81491506dc0a Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 17 Jun 2026 21:52:08 +1200 Subject: [PATCH 005/161] refactor(pkg/strvals): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- pkg/strvals/literal_parser_test.go | 45 +++++------ pkg/strvals/parser_test.go | 119 +++++++++++++---------------- 2 files changed, 73 insertions(+), 91 deletions(-) diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index cc3d73d50..d7892844f 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -20,6 +20,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "sigs.k8s.io/yaml" ) @@ -278,27 +281,25 @@ func TestParseLiteral(t *testing.T) { got, err := ParseLiteral(tt.str) if err != nil { if !tt.err { - t.Fatalf("%s: %s", tt.str, err) + require.NoError(t, err, tt.str) } continue } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.str) + assert.Fail(t, "Expected error. Got nil", tt.str) } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.str) } } } @@ -385,33 +386,31 @@ func TestParseLiteralInto(t *testing.T) { for _, tt := range tests { if err := ParseLiteralInto(tt.input, tt.got); err != nil { - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.input) + assert.Fail(t, "Expected error. Got nil", tt.input) } if tt.input2 != "" { if err := ParseLiteralInto(tt.input2, tt.got); err != nil { - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.input2) + assert.Fail(t, "Expected error. Got nil", tt.input2) } } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(tt.got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.input) } } } @@ -452,30 +451,28 @@ func TestParseLiteralNestedLevels(t *testing.T) { if tt.err { if tt.errStr != "" { if err.Error() != tt.errStr { - t.Errorf("Expected error: %s. Got error: %s", tt.errStr, err.Error()) + assert.Equal(t, tt.errStr, err.Error()) } } continue } - t.Fatalf("%s: %s", tt.str, err) + require.NoError(t, err, tt.str) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.str) + assert.Fail(t, "Expected error. Got nil", tt.str) } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.str) } } } diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index e3f8b9d8e..1a9559236 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -20,6 +20,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "sigs.k8s.io/yaml" ) @@ -78,24 +81,24 @@ func TestSetIndex(t *testing.T) { got, err := setIndex(tt.initial, tt.add, tt.val) if err != nil && tt.err == false { - t.Fatalf("%s: Expected no error but error returned", tt.name) + require.Fail(t, "Expected no error but error returned", tt.name) } else if err == nil && tt.err == true { - t.Fatalf("%s: Expected error but no error returned", tt.name) + require.Fail(t, "Expected error but no error returned", tt.name) } if len(got) != len(tt.expect) { - t.Fatalf("%s: Expected length %d, got %d", tt.name, len(tt.expect), len(got)) + require.Len(t, got, len(tt.expect), tt.name) } if !tt.err { if gg := got[tt.add].(int); gg != tt.val { - t.Errorf("%s, Expected value %d, got %d", tt.name, tt.val, gg) + assert.Equal(t, tt.val, gg, tt.name) } } for k, v := range got { if v != tt.expect[k] { - t.Errorf("%s, Expected value %d, got %d", tt.name, tt.expect[k], v) + assert.Equal(t, tt.expect[k], v, tt.name) } } } @@ -384,23 +387,21 @@ func TestParseSet(t *testing.T) { if tt.err { continue } - t.Fatalf("%s: %s", tt.str, err) + require.NoError(t, err, tt.str) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.str) + assert.Fail(t, "Expected error. Got nil", tt.str) } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.str) } } for _, tt := range testsString { @@ -409,23 +410,21 @@ func TestParseSet(t *testing.T) { if tt.err { continue } - t.Fatalf("%s: %s", tt.str, err) + require.NoError(t, err, tt.str) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.str) + assert.Fail(t, "Expected error. Got nil", tt.str) } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.str) } } } @@ -513,32 +512,30 @@ func TestParseInto(t *testing.T) { } for _, tt := range tests { if err := ParseInto(tt.input, tt.got); err != nil { - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.input) + assert.Fail(t, "Expected error. Got nil", tt.input) } if tt.input2 != "" { if err := ParseInto(tt.input2, tt.got); err != nil { - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.input2) + assert.Fail(t, "Expected error. Got nil", tt.input2) } } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(tt.got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.input) } } } @@ -560,20 +557,18 @@ func TestParseIntoString(t *testing.T) { } if err := ParseIntoString(input, got); err != nil { - t.Fatal(err) + require.NoError(t, err) } y1, err := yaml.Marshal(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + assert.Equal(t, string(y1), string(y2), input) } } @@ -658,22 +653,22 @@ func TestParseJSON(t *testing.T) { if tt.err { continue } - t.Fatalf("%s: %s", tt.input, err) + require.NoError(t, err, tt.input) } if tt.err { - t.Fatalf("%s: Expected error. Got nil", tt.input) + require.Fail(t, "Expected error. Got nil", tt.input) } y1, err := yaml.Marshal(tt.expect) if err != nil { - t.Fatalf("Error serializing expected value: %s", err) + require.NoError(t, err, "Error serializing expected value") } y2, err := yaml.Marshal(tt.got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.input) } } } @@ -686,28 +681,24 @@ func TestParseFile(t *testing.T) { rs2v := func(rs []rune) (any, error) { v := string(rs) if v != "path1" { - t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) + assert.Equal(t, "path1", v, "%s: runesToVal", input) return "", nil } return "value1", nil } got, err := ParseFile(input, rs2v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y1, err := yaml.Marshal(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + assert.Equal(t, string(y1), string(y2), input) } } @@ -720,27 +711,25 @@ func TestParseIntoFile(t *testing.T) { rs2v := func(rs []rune) (any, error) { v := string(rs) if v != "path1" { - t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) + assert.Equal(t, "path1", v, "%s: runesToVal", input) return "", nil } return "value1", nil } if err := ParseIntoFile(input, got, rs2v); err != nil { - t.Fatal(err) + require.NoError(t, err) } y1, err := yaml.Marshal(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + assert.Equal(t, string(y1), string(y2), input) } } @@ -748,12 +737,10 @@ func TestToYAML(t *testing.T) { // The TestParse does the hard part. We just verify that YAML formatting is // happening. o, err := ToYAML("name=value") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := "name: value" if o != expect { - t.Errorf("Expected %q, got %q", expect, o) + assert.Equal(t, expect, o) } } @@ -792,28 +779,26 @@ func TestParseSetNestedLevels(t *testing.T) { if tt.err { if tt.errStr != "" { if err.Error() != tt.errStr { - t.Errorf("Expected error: %s. Got error: %s", tt.errStr, err.Error()) + assert.Equal(t, tt.errStr, err.Error()) } } continue } - t.Fatalf("%s: %s", tt.str, err) + require.NoError(t, err, tt.str) } if tt.err { - t.Errorf("%s: Expected error. Got nil", tt.str) + assert.Fail(t, "Expected error. Got nil", tt.str) } y1, err := yaml.Marshal(tt.expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) y2, err := yaml.Marshal(got) if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) + require.NoError(t, err, "Error serializing parsed value") } if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) + assert.Equal(t, string(y1), string(y2), tt.str) } } } From b42faba9d293d45d2654dac5b540adb5b50e5b4f Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 15:15:19 +1200 Subject: [PATCH 006/161] refactor(repotest): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- pkg/repo/v1/repotest/server.go | 76 +++++++++-------------------- pkg/repo/v1/repotest/server_test.go | 70 +++++++------------------- 2 files changed, 40 insertions(+), 106 deletions(-) diff --git a/pkg/repo/v1/repotest/server.go b/pkg/repo/v1/repotest/server.go index 61dcd6931..06cdc9172 100644 --- a/pkg/repo/v1/repotest/server.go +++ b/pkg/repo/v1/repotest/server.go @@ -30,6 +30,8 @@ import ( "github.com/distribution/distribution/v3/registry" _ "github.com/distribution/distribution/v3/registry/auth/htpasswd" // used for docker test registry _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" // used for docker test registry + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/crypto/bcrypt" "sigs.k8s.io/yaml" @@ -44,9 +46,8 @@ func BasicAuthMiddleware(t *testing.T) http.HandlerFunc { t.Helper() return http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if !ok || username != "username" || password != "password" { - t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) - } + assert.True(t, ok && username == "username" && password == "password", + "Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) }) } @@ -97,9 +98,8 @@ func NewTempServer(t *testing.T, options ...ServerOption) *Server { t.Cleanup(func() { os.RemoveAll(srv.docroot) }) if srv.chartSourceGlob != "" { - if _, err := srv.CopyCharts(srv.chartSourceGlob); err != nil { - t.Fatal(err) - } + _, err := srv.CopyCharts(srv.chartSourceGlob) + require.NoError(t, err) } return srv @@ -109,9 +109,7 @@ func NewTempServer(t *testing.T, options ...ServerOption) *Server { func newServer(t *testing.T, docroot string, options ...ServerOption) *Server { t.Helper() absdocroot, err := filepath.Abs(docroot) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) s := &Server{ docroot: absdocroot, @@ -131,9 +129,7 @@ func newServer(t *testing.T, docroot string, options ...ServerOption) *Server { s.start() // Add the testing repository as the only repo. Server must be started for the server's URL to be valid - if err := setTestingRepository(s.URL(), filepath.Join(s.docroot, "repositories.yaml")); err != nil { - t.Fatal(err) - } + require.NoError(t, setTestingRepository(s.URL(), filepath.Join(s.docroot, "repositories.yaml"))) return s } @@ -169,22 +165,16 @@ func NewOCIServer(t *testing.T, dir string) (*OCIServer, error) { testUsername, testPassword := "username", "password" pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) - if err != nil { - t.Fatal("error generating bcrypt password for test htpasswd file") - } + require.NoError(t, err, "error generating bcrypt password for test htpasswd file") htpasswdPath := filepath.Join(dir, testHtpasswdFileBasename) err = os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644) - if err != nil { - t.Fatal("error creating test htpasswd file") - } + require.NoError(t, err, "error creating test htpasswd file") // Registry config config := &configuration.Configuration{} lnCfg := net.ListenConfig{} ln, err := lnCfg.Listen(t.Context(), "tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("error finding free port for test registry: %v", err) - } + require.NoError(t, err, "error finding free port for test registry") defer ln.Close() port := ln.Addr().(*net.TCPAddr).Port @@ -201,9 +191,7 @@ func NewOCIServer(t *testing.T, dir string) (*OCIServer, error) { registryURL := fmt.Sprintf("localhost:%d", port) r, err := registry.NewRegistry(t.Context(), config) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return &OCIServer{ Registry: r, @@ -237,53 +225,37 @@ func (srv *OCIServer) RunWithReturn(t *testing.T, opts ...OCIServerOpt) *OCIServ ociRegistry.ClientOptWriter(os.Stdout), ociRegistry.ClientOptCredentialsFile(credentialsFile), ) - if err != nil { - t.Fatalf("error creating registry client: %v", err) - } + require.NoError(t, err, "error creating registry client") err = registryClient.Login( srv.RegistryURL, ociRegistry.LoginOptBasicAuth(srv.TestUsername, srv.TestPassword), ociRegistry.LoginOptInsecure(true), ociRegistry.LoginOptPlainText(true)) - if err != nil { - t.Fatalf("error logging into registry with good credentials: %v", err) - } + require.NoError(t, err, "error logging into registry with good credentials") ref := srv.RegistryURL + "/u/ocitestuser/oci-dependent-chart:0.1.0" err = chartutil.ExpandFile(srv.Dir, filepath.Join(srv.Dir, "oci-dependent-chart-0.1.0.tgz")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // valid chart ch, err := loader.LoadDir(filepath.Join(srv.Dir, "oci-dependent-chart")) - if err != nil { - t.Fatal("error loading chart") - } + require.NoError(t, err, "error loading chart") err = os.RemoveAll(filepath.Join(srv.Dir, "oci-dependent-chart")) - if err != nil { - t.Fatal("error removing chart before push") - } + require.NoError(t, err, "error removing chart before push") // save it back to disk.. absPath, err := chartutil.Save(ch, srv.Dir) - if err != nil { - t.Fatal("could not create chart archive") - } + require.NoError(t, err, "could not create chart archive") // load it into memory... contentBytes, err := os.ReadFile(absPath) - if err != nil { - t.Fatal("could not load chart into memory") - } + require.NoError(t, err, "could not load chart into memory") result, err := registryClient.Push(contentBytes, ref) - if err != nil { - t.Fatalf("error pushing dependent chart: %s", err) - } + require.NoError(t, err, "error pushing dependent chart") t.Logf("Manifest.Digest: %s, Manifest.Size: %d, "+ "Config.Digest: %s, Config.Size: %d, "+ "Chart.Digest: %s, Chart.Size: %d", @@ -306,14 +278,10 @@ func (srv *OCIServer) RunWithReturn(t *testing.T, opts ...OCIServerOpt) *OCIServ absPath = filepath.Join(srv.Dir, fmt.Sprintf("%s-%s.tgz", c.Metadata.Name, c.Metadata.Version)) contentBytes, err = os.ReadFile(absPath) - if err != nil { - t.Fatal("could not load chart into memory") - } + require.NoError(t, err, "could not load chart into memory") result, err = registryClient.Push(contentBytes, dependingRef) - if err != nil { - t.Fatalf("error pushing depending chart: %s", err) - } + require.NoError(t, err, "error pushing depending chart") t.Logf("Manifest.Digest: %s, Manifest.Size: %d, "+ "Config.Digest: %s, Config.Size: %d, "+ "Chart.Digest: %s, Chart.Size: %d", diff --git a/pkg/repo/v1/repotest/server_test.go b/pkg/repo/v1/repotest/server_test.go index 1364fc9c9..7008e2305 100644 --- a/pkg/repo/v1/repotest/server_test.go +++ b/pkg/repo/v1/repotest/server_test.go @@ -22,6 +22,7 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" @@ -40,18 +41,11 @@ func TestServer(t *testing.T) { defer srv.Stop() c, err := srv.CopyCharts("testdata/*.tgz") - if err != nil { - // Some versions of Go don't correctly fire defer on Fatal. - t.Fatal(err) - } + require.NoError(t, err) - if len(c) != 1 { - t.Errorf("Unexpected chart count: %d", len(c)) - } + assert.Len(t, c, 1) - if filepath.Base(c[0]) != "examplechart-0.1.0.tgz" { - t.Errorf("Unexpected chart: %s", c[0]) - } + assert.Equal(t, "examplechart-0.1.0.tgz", filepath.Base(c[0])) req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/examplechart-0.1.0.tgz", http.NoBody) require.NoError(t, err) @@ -60,9 +54,7 @@ func TestServer(t *testing.T) { require.NoError(t, err) res.Body.Close() - if res.ContentLength < 500 { - t.Errorf("Expected at least 500 bytes of data, got %d", res.ContentLength) - } + assert.GreaterOrEqual(t, res.ContentLength, int64(500)) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml", http.NoBody) require.NoError(t, err) @@ -73,27 +65,19 @@ func TestServer(t *testing.T) { require.NoError(t, err) m := repo.NewIndexFile() - if err := yaml.Unmarshal(data, m); err != nil { - t.Fatal(err) - } + require.NoError(t, yaml.Unmarshal(data, m)) - if l := len(m.Entries); l != 1 { - t.Fatalf("Expected 1 entry, got %d", l) - } + require.Len(t, m.Entries, 1) expect := "examplechart" - if !m.Has(expect, "0.1.0") { - t.Errorf("missing %q", expect) - } + assert.True(t, m.Has(expect, "0.1.0"), "missing %q", expect) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml-nosuchthing", http.NoBody) require.NoError(t, err) res, err = client.Do(req) require.NoError(t, err) res.Body.Close() - if res.StatusCode != http.StatusNotFound { - t.Fatalf("Expected 404, got %d", res.StatusCode) - } + require.Equal(t, http.StatusNotFound, res.StatusCode) } func TestNewTempServer(t *testing.T) { @@ -125,9 +109,7 @@ func TestNewTempServer(t *testing.T) { ) defer srv.Stop() - if srv.srv.URL == "" { - t.Fatal("unstarted server") - } + require.NotEmpty(t, srv.srv.URL, "unstarted server") client := srv.Client() @@ -137,9 +119,7 @@ func TestNewTempServer(t *testing.T) { res, err := client.Do(req) require.NoError(t, err) res.Body.Close() - if res.StatusCode != http.StatusOK { - t.Errorf("Expected 200, got %d", res.StatusCode) - } + assert.Equal(t, http.StatusOK, res.StatusCode) } { req, err := http.NewRequestWithContext(t.Context(), http.MethodHead, srv.URL()+"/examplechart-0.1.0.tgz", http.NoBody) @@ -147,18 +127,14 @@ func TestNewTempServer(t *testing.T) { res, err := client.Do(req) require.NoError(t, err) res.Body.Close() - if res.StatusCode != http.StatusOK { - t.Errorf("Expected 200, got %d", res.StatusCode) - } + assert.Equal(t, http.StatusOK, res.StatusCode) } req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/examplechart-0.1.0.tgz", http.NoBody) require.NoError(t, err) res, err := client.Do(req) require.NoError(t, err) res.Body.Close() - if res.ContentLength < 500 { - t.Errorf("Expected at least 500 bytes of data, got %d", res.ContentLength) - } + assert.GreaterOrEqual(t, res.ContentLength, int64(500)) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml", http.NoBody) require.NoError(t, err) res, err = client.Do(req) @@ -167,24 +143,16 @@ func TestNewTempServer(t *testing.T) { res.Body.Close() require.NoError(t, err) m := repo.NewIndexFile() - if err := yaml.Unmarshal(data, m); err != nil { - t.Fatal(err) - } - if l := len(m.Entries); l != 1 { - t.Fatalf("Expected 1 entry, got %d", l) - } + require.NoError(t, yaml.Unmarshal(data, m)) + require.Len(t, m.Entries, 1) expect := "examplechart" - if !m.Has(expect, "0.1.0") { - t.Errorf("missing %q", expect) - } + assert.True(t, m.Has(expect, "0.1.0"), "missing %q", expect) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml-nosuchthing", http.NoBody) require.NoError(t, err) res, err = client.Do(req) require.NoError(t, err) res.Body.Close() - if res.StatusCode != http.StatusNotFound { - t.Fatalf("Expected 404, got %d", res.StatusCode) - } + require.Equal(t, http.StatusNotFound, res.StatusCode) }) } } @@ -199,7 +167,5 @@ func TestNewTempServer_TLS(t *testing.T) { ) defer srv.Stop() - if !strings.HasPrefix(srv.URL(), "https://") { - t.Fatal("non-TLS server") - } + require.True(t, strings.HasPrefix(srv.URL(), "https://"), "non-TLS server") } From 3ce02c585a18b38c5dba1177a54c3a0322c53d3c Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 16:26:28 +1200 Subject: [PATCH 007/161] refactor(internal): convert tests to testify assert/require Convert internal/fileutil, internal/tlsutil, and internal/resolver test files from native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) to github.com/stretchr/testify equivalents (assert.X, require.X). Signed-off-by: George Jenkins --- internal/fileutil/fileutil_test.go | 70 +++++++++--------------------- internal/resolver/resolver_test.go | 51 +++++++++------------- internal/tlsutil/tls_test.go | 55 +++++++---------------- 3 files changed, 56 insertions(+), 120 deletions(-) diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go index 71fcae177..07cbe7695 100644 --- a/internal/fileutil/fileutil_test.go +++ b/internal/fileutil/fileutil_test.go @@ -22,6 +22,9 @@ import ( "path/filepath" "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // TestAtomicWriteFile tests the happy path of AtomicWriteFile function. @@ -35,28 +38,17 @@ func TestAtomicWriteFile(t *testing.T) { mode := os.FileMode(0644) err := AtomicWriteFile(testpath, reader, mode) - if err != nil { - t.Errorf("AtomicWriteFile error: %s", err) - } + assert.NoError(t, err) got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if stringContent != string(got) { - t.Fatalf("expected: %s, got: %s", stringContent, string(got)) - } + require.Equal(t, stringContent, string(got)) gotinfo, err := os.Stat(testpath) - if err != nil { - t.Fatal(err) - } - - if mode != gotinfo.Mode() { - t.Fatalf("expected %s: to be the same mode as %s", - mode, gotinfo.Mode()) - } + require.NoError(t, err) + + require.Equal(t, mode, gotinfo.Mode()) } // TestAtomicWriteFile_CreateTempError tests the error path when os.CreateTemp fails @@ -67,9 +59,7 @@ func TestAtomicWriteFile_CreateTempError(t *testing.T) { mode := os.FileMode(0644) err := AtomicWriteFile(invalidPath, reader, mode) - if err == nil { - t.Error("Expected error when CreateTemp fails, but got nil") - } + assert.Error(t, err, "Expected error when CreateTemp fails") } // TestAtomicWriteFile_EmptyContent tests with empty content @@ -81,18 +71,12 @@ func TestAtomicWriteFile_EmptyContent(t *testing.T) { mode := os.FileMode(0644) err := AtomicWriteFile(testpath, reader, mode) - if err != nil { - t.Errorf("AtomicWriteFile error with empty content: %s", err) - } + assert.NoError(t, err, "AtomicWriteFile error with empty content") got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(got) != 0 { - t.Fatalf("expected empty content, got: %s", string(got)) - } + require.Empty(t, got) } // TestAtomicWriteFile_LargeContent tests with large content @@ -106,18 +90,12 @@ func TestAtomicWriteFile_LargeContent(t *testing.T) { mode := os.FileMode(0644) err := AtomicWriteFile(testpath, reader, mode) - if err != nil { - t.Errorf("AtomicWriteFile error with large content: %s", err) - } + assert.NoError(t, err, "AtomicWriteFile error with large content") got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if largeContent != string(got) { - t.Fatalf("expected large content to match, got different length: %d vs %d", len(largeContent), len(got)) - } + require.Equal(t, largeContent, string(got)) } // TestPlatformAtomicWriteFile_OverwritesExisting verifies that the platform @@ -127,21 +105,13 @@ func TestPlatformAtomicWriteFile_OverwritesExisting(t *testing.T) { path := filepath.Join(dir, "overwrite_test") first := bytes.NewReader([]byte("first")) - if err := PlatformAtomicWriteFile(path, first, 0644); err != nil { - t.Fatalf("first write failed: %v", err) - } + require.NoError(t, PlatformAtomicWriteFile(path, first, 0644), "first write failed") second := bytes.NewReader([]byte("second")) - if err := PlatformAtomicWriteFile(path, second, 0644); err != nil { - t.Fatalf("second write failed: %v", err) - } + require.NoError(t, PlatformAtomicWriteFile(path, second, 0644), "second write failed") contents, err := os.ReadFile(path) - if err != nil { - t.Fatalf("failed reading result: %v", err) - } + require.NoError(t, err, "failed reading result") - if string(contents) != "second" { - t.Fatalf("expected file to be overwritten, got %q", string(contents)) - } + require.Equal(t, "second", string(contents)) } diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index 1e33837a9..547419e17 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -19,6 +19,9 @@ import ( "runtime" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/registry" ) @@ -149,34 +152,24 @@ func TestResolve(t *testing.T) { if tt.err { return } - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Fatalf("Expected error in test %q", tt.name) + require.Failf(t, "Expected error in test %q", tt.name) } - if h, err := HashReq(tt.req, tt.expect.Dependencies); err != nil { - t.Fatal(err) - } else if h != l.Digest { - t.Errorf("%q: hashes don't match.", tt.name) - } + h, err := HashReq(tt.req, tt.expect.Dependencies) + require.NoError(t, err) + assert.Equal(t, l.Digest, h, "%q: hashes don't match.", tt.name) // Check fields. - if len(l.Dependencies) != len(tt.req) { - t.Errorf("%s: wrong number of dependencies in lock", tt.name) - } + assert.Len(t, l.Dependencies, len(tt.req), "%s: wrong number of dependencies in lock", tt.name) d0 := l.Dependencies[0] e0 := tt.expect.Dependencies[0] - if d0.Name != e0.Name { - t.Errorf("%s: expected name %s, got %s", tt.name, e0.Name, d0.Name) - } - if d0.Repository != e0.Repository { - t.Errorf("%s: expected repo %s, got %s", tt.name, e0.Repository, d0.Repository) - } - if d0.Version != e0.Version { - t.Errorf("%s: expected version %s, got %s", tt.name, e0.Version, d0.Version) - } + assert.Equal(t, e0.Name, d0.Name, tt.name) + assert.Equal(t, e0.Repository, d0.Repository, tt.name) + assert.Equal(t, e0.Version, d0.Version, tt.name) }) } } @@ -231,13 +224,11 @@ func TestHashReq(t *testing.T) { {Name: "alpine", Version: tt.lockVersion, Repository: "http://localhost:8879/charts"}, } h, err := HashReq(req, lock) - if err != nil { - t.Fatal(err) - } - if !tt.wantError && expect != h { - t.Errorf("Expected %q, got %q", expect, h) - } else if tt.wantError && expect == h { - t.Errorf("Expected not %q, but same", expect) + require.NoError(t, err) + if !tt.wantError { + assert.Equal(t, expect, h) + } else { + assert.NotEqual(t, expect, h, "Expected not %q, but same", expect) } }) } @@ -293,18 +284,16 @@ func TestGetLocalPath(t *testing.T) { if tt.err { return } - t.Fatal(err) + require.NoError(t, err) } if tt.err { - t.Fatalf("Expected error in test %q", tt.name) + require.Failf(t, "Expected error in test %q", tt.name) } expect := tt.expect if runtime.GOOS == "windows" { expect = tt.winExpect } - if p != expect { - t.Errorf("%q: expected %q, got %q", tt.name, expect, p) - } + assert.Equal(t, expect, p, tt.name) }) } } diff --git a/internal/tlsutil/tls_test.go b/internal/tlsutil/tls_test.go index e6859f99f..324b00969 100644 --- a/internal/tlsutil/tls_test.go +++ b/internal/tlsutil/tls_test.go @@ -19,6 +19,9 @@ package tlsutil import ( "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const tlsTestDir = "../../testdata" @@ -32,9 +35,7 @@ const ( func testfile(t *testing.T, file string) (path string) { t.Helper() path, err := filepath.Abs(filepath.Join(tlsTestDir, file)) - if err != nil { - t.Fatalf("error getting absolute path to test file %q: %v", file, err) - } + require.NoError(t, err, "error getting absolute path to test file %q", file) return path } @@ -50,38 +51,22 @@ func TestNewTLSConfig(t *testing.T) { WithCertKeyPairFiles(certFile, keyFile), WithCAFile(caCertFile), ) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) - if got := len(cfg.Certificates); got != 1 { - t.Fatalf("expecting 1 client certificates, got %d", got) - } - if cfg.InsecureSkipVerify { - t.Fatal("insecure skip verify mismatch, expecting false") - } - if cfg.RootCAs == nil { - t.Fatal("mismatch tls RootCAs, expecting non-nil") - } + require.Len(t, cfg.Certificates, 1) + require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") + require.NotNil(t, cfg.RootCAs, "mismatch tls RootCAs, expecting non-nil") } { cfg, err := NewTLSConfig( WithInsecureSkipVerify(insecureSkipTLSVerify), WithCAFile(caCertFile), ) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) - if got := len(cfg.Certificates); got != 0 { - t.Fatalf("expecting 0 client certificates, got %d", got) - } - if cfg.InsecureSkipVerify { - t.Fatal("insecure skip verify mismatch, expecting false") - } - if cfg.RootCAs == nil { - t.Fatal("mismatch tls RootCAs, expecting non-nil") - } + require.Empty(t, cfg.Certificates) + require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") + require.NotNil(t, cfg.RootCAs, "mismatch tls RootCAs, expecting non-nil") } { @@ -89,18 +74,10 @@ func TestNewTLSConfig(t *testing.T) { WithInsecureSkipVerify(insecureSkipTLSVerify), WithCertKeyPairFiles(certFile, keyFile), ) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) - if got := len(cfg.Certificates); got != 1 { - t.Fatalf("expecting 1 client certificates, got %d", got) - } - if cfg.InsecureSkipVerify { - t.Fatal("insecure skip verify mismatch, expecting false") - } - if cfg.RootCAs != nil { - t.Fatal("mismatch tls RootCAs, expecting nil") - } + require.Len(t, cfg.Certificates, 1) + require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") + require.Nil(t, cfg.RootCAs, "mismatch tls RootCAs, expecting nil") } } From 8b0a167484a7f6de4a2cb12bf81641873a275d7b Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 17 Jun 2026 21:36:47 +1200 Subject: [PATCH 008/161] refactor(pkg/registry): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- pkg/registry/chart_test.go | 39 +++++++------------ pkg/registry/client_test.go | 31 +++++---------- pkg/registry/plugin_test.go | 17 +++----- pkg/registry/reference_test.go | 66 ++++++++++--------------------- pkg/registry/tag_test.go | 71 +++++++++------------------------- pkg/registry/transport_test.go | 35 ++++++----------- 6 files changed, 79 insertions(+), 180 deletions(-) diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index 0b247601b..23a32506d 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -17,11 +17,12 @@ limitations under the License. package registry // import "helm.sh/helm/v4/pkg/registry" import ( - "reflect" "testing" "time" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" chart "helm.sh/helm/v4/pkg/chart/v2" ) @@ -147,10 +148,7 @@ func TestGenerateOCIChartAnnotations(t *testing.T) { for _, tt := range tests { result := generateChartOCIAnnotations(tt.chart, nowString) - - if !reflect.DeepEqual(tt.expect, result) { - t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result) - } + assert.Equal(t, tt.expect, result, tt.name) } } @@ -218,10 +216,7 @@ func TestGenerateOCIAnnotations(t *testing.T) { for _, tt := range tests { result := generateOCIAnnotations(tt.chart, nowString) - - if !reflect.DeepEqual(tt.expect, result) { - t.Errorf("%s: expected map %v, got %v", tt.name, tt.expect, result) - } + assert.Equal(t, tt.expect, result, tt.name) } } @@ -237,29 +232,23 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { result := generateOCIAnnotations(testChart, nowTimeString) // Check that created annotation exists - if _, ok := result[ocispec.AnnotationCreated]; !ok { - t.Errorf("%s annotation not created", ocispec.AnnotationCreated) - } + _, ok := result[ocispec.AnnotationCreated] + assert.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) // Verify value of created artifact in RFC3339 format - if _, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]); err != nil { - t.Errorf("%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) - } + _, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) + assert.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) // Verify default creation time set result = generateOCIAnnotations(testChart, "") // Check that created annotation exists - if _, ok := result[ocispec.AnnotationCreated]; !ok { - t.Errorf("%s annotation not created", ocispec.AnnotationCreated) - } + _, ok = result[ocispec.AnnotationCreated] + require.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) - if createdTimeAnnotation, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]); err != nil { - t.Errorf("%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) + createdTimeAnnotation, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) + require.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) - // Verify creation annotation after time test began - if !nowTime.Before(createdTimeAnnotation) { - t.Errorf("%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) - } - } + // Verify creation annotation after (or equals) time test began + assert.False(t, nowTime.Before(createdTimeAnnotation), "%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) } diff --git a/pkg/registry/client_test.go b/pkg/registry/client_test.go index 702dfff69..97b7c7c4c 100644 --- a/pkg/registry/client_test.go +++ b/pkg/registry/client_test.go @@ -25,6 +25,7 @@ import ( "testing" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "oras.land/oras-go/v2/content/memory" ) @@ -77,22 +78,15 @@ func TestLogin_ResetsForceAttemptOAuth2_OnSuccess(t *testing.T) { ClientOptWriter(io.Discard), ClientOptCredentialsFile(credFile), ) - if err != nil { - t.Fatalf("NewClient error: %v", err) - } + require.NoError(t, err, "NewClient error") - if c.authorizer == nil || c.authorizer.ForceAttemptOAuth2 { - t.Fatal("expected ForceAttemptOAuth2 default to be false") - } + require.NotNil(t, c.authorizer) + require.False(t, c.authorizer.ForceAttemptOAuth2, "expected ForceAttemptOAuth2 default to be false") // Call Login with plain HTTP against our test server - if err := c.Login(host, LoginOptPlainText(true), LoginOptBasicAuth("u", "p")); err != nil { - t.Fatalf("Login error: %v", err) - } + require.NoError(t, c.Login(host, LoginOptPlainText(true), LoginOptBasicAuth("u", "p")), "Login error") - if c.authorizer.ForceAttemptOAuth2 { - t.Error("ForceAttemptOAuth2 should be false after successful Login") - } + assert.False(t, c.authorizer.ForceAttemptOAuth2, "ForceAttemptOAuth2 should be false after successful Login") } // Verifies that Login restores ForceAttemptOAuth2 to false even when ping fails. @@ -109,16 +103,12 @@ func TestLogin_ResetsForceAttemptOAuth2_OnFailure(t *testing.T) { ClientOptWriter(io.Discard), ClientOptCredentialsFile(credFile), ) - if err != nil { - t.Fatalf("NewClient error: %v", err) - } + require.NoError(t, err, "NewClient error") // Invoke Login, expect an error but ForceAttemptOAuth2 must end false _ = c.Login(host, LoginOptPlainText(true), LoginOptBasicAuth("u", "p")) - if c.authorizer.ForceAttemptOAuth2 { - t.Error("ForceAttemptOAuth2 should be false after failed Login") - } + assert.False(t, c.authorizer.ForceAttemptOAuth2, "ForceAttemptOAuth2 should be false after failed Login") } // TestWarnIfHostHasPath verifies that warnIfHostHasPath correctly detects path components. @@ -159,10 +149,7 @@ func TestWarnIfHostHasPath(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := warnIfHostHasPath(tt.host) - if got != tt.wantWarn { - t.Errorf("warnIfHostHasPath(%q) = %v, want %v", tt.host, got, tt.wantWarn) - } + assert.Equal(t, tt.wantWarn, warnIfHostHasPath(tt.host)) }) } } diff --git a/pkg/registry/plugin_test.go b/pkg/registry/plugin_test.go index 61995ece9..bb557c5b8 100644 --- a/pkg/registry/plugin_test.go +++ b/pkg/registry/plugin_test.go @@ -18,6 +18,9 @@ package registry import ( "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetPluginName(t *testing.T) { @@ -74,20 +77,12 @@ func TestGetPluginName(t *testing.T) { pluginName, err := GetPluginName(tt.source) if tt.expectErr { - if err == nil { - t.Error("expected error but got none") - } + assert.Error(t, err, "expected error but got none") return } - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - if pluginName != tt.expected { - t.Errorf("expected plugin name %q, got %q", tt.expected, pluginName) - } + require.NoError(t, err) + assert.Equal(t, tt.expected, pluginName) }) } } diff --git a/pkg/registry/reference_test.go b/pkg/registry/reference_test.go index b6872cc37..f1a87fefc 100644 --- a/pkg/registry/reference_test.go +++ b/pkg/registry/reference_test.go @@ -16,31 +16,21 @@ limitations under the License. package registry -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func verify(t *testing.T, actual reference, registry, repository, tag, digest string) { t.Helper() - if registry != actual.orasReference.Registry { - t.Errorf("Oras reference registry expected %v actual %v", registry, actual.Registry) - } - if repository != actual.orasReference.Repository { - t.Errorf("Oras reference repository expected %v actual %v", repository, actual.Repository) - } - if tag != actual.orasReference.Reference { - t.Errorf("Oras reference reference expected %v actual %v", tag, actual.Tag) - } - if registry != actual.Registry { - t.Errorf("Registry expected %v actual %v", registry, actual.Registry) - } - if repository != actual.Repository { - t.Errorf("Repository expected %v actual %v", repository, actual.Repository) - } - if tag != actual.Tag { - t.Errorf("Tag expected %v actual %v", tag, actual.Tag) - } - if digest != actual.Digest { - t.Errorf("Digest expected %v actual %v", digest, actual.Digest) - } + assert.Equal(t, registry, actual.orasReference.Registry, "Oras reference registry") + assert.Equal(t, repository, actual.orasReference.Repository, "Oras reference repository") + assert.Equal(t, tag, actual.orasReference.Reference, "Oras reference reference") + assert.Equal(t, registry, actual.Registry, "Registry") + assert.Equal(t, repository, actual.Repository, "Repository") + assert.Equal(t, tag, actual.Tag, "Tag") + assert.Equal(t, digest, actual.Digest, "Digest") expectedString := registry if repository != "" { expectedString = expectedString + "/" + repository @@ -50,51 +40,35 @@ func verify(t *testing.T, actual reference, registry, repository, tag, digest st } else { expectedString = expectedString + "@" + digest } - if actual.String() != expectedString { - t.Errorf("String expected %s actual %s", expectedString, actual.String()) - } + assert.Equal(t, expectedString, actual.String(), "String") } func TestNewReference(t *testing.T) { actual, err := newReference("registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") actual, err = newReference("oci://registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") actual, err = newReference("a/b:1@c") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "a", "b", "1", "c") actual, err = newReference("a/b:@") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "a", "b", "", "") actual, err = newReference("registry.example.com/repository:1.0+001") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0_001", "") actual, err = newReference("thing:1.0") - if err == nil { - t.Errorf("Expect error error %v", err) - } + assert.Error(t, err) verify(t, actual, "", "", "", "") actual, err = newReference("registry.example.com/the/repository@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - if err != nil { - t.Errorf("Unexpected error %v", err) - } + assert.NoError(t, err) verify(t, actual, "registry.example.com", "the/repository", "", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") } diff --git a/pkg/registry/tag_test.go b/pkg/registry/tag_test.go index e3ec47703..830eac7e1 100644 --- a/pkg/registry/tag_test.go +++ b/pkg/registry/tag_test.go @@ -17,32 +17,25 @@ limitations under the License. package registry import ( - "strings" "testing" + + "github.com/stretchr/testify/require" ) func TestGetTagMatchingVersionOrConstraint_ExactMatch(t *testing.T) { tags := []string{"1.0.0", "1.2.3", "2.0.0"} got, err := GetTagMatchingVersionOrConstraint(tags, "1.2.3") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.2.3" { - t.Fatalf("expected exact match '1.2.3', got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.2.3", got, "expected exact match") } func TestGetTagMatchingVersionOrConstraint_EmptyVersionWildcard(t *testing.T) { // Includes a non-semver tag which should be skipped tags := []string{"latest", "0.9.0", "1.0.0"} got, err := GetTagMatchingVersionOrConstraint(tags, "") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + require.NoError(t, err) // Should pick the first valid semver tag in order, which is 0.9.0 - if got != "0.9.0" { - t.Fatalf("expected '0.9.0', got %q", got) - } + require.Equal(t, "0.9.0", got) } func TestGetTagMatchingVersionOrConstraint_ConstraintRange(t *testing.T) { @@ -50,73 +43,47 @@ func TestGetTagMatchingVersionOrConstraint_ConstraintRange(t *testing.T) { // Caret range got, err := GetTagMatchingVersionOrConstraint(tags, "^1.0.0") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.0.0" { // first match in order - t.Fatalf("expected '1.0.0', got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.0.0", got, "first match in order") // Compound range got, err = GetTagMatchingVersionOrConstraint(tags, ">=1.0.0 <2.0.0") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.0.0" { - t.Fatalf("expected '1.0.0', got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.0.0", got) } func TestGetTagMatchingVersionOrConstraint_InvalidConstraint(t *testing.T) { tags := []string{"1.0.0"} _, err := GetTagMatchingVersionOrConstraint(tags, ">a1") - if err == nil { - t.Fatal("expected error for invalid constraint") - } + require.Error(t, err, "expected error for invalid constraint") } func TestGetTagMatchingVersionOrConstraint_NoMatches(t *testing.T) { tags := []string{"0.1.0", "0.2.0"} _, err := GetTagMatchingVersionOrConstraint(tags, ">=1.0.0") - if err == nil { - t.Fatal("expected error when no tags match") - } - if !strings.Contains(err.Error(), ">=1.0.0") { - t.Fatalf("expected error to contain version string, got: %v", err) - } + require.Error(t, err, "expected error when no tags match") + require.Contains(t, err.Error(), ">=1.0.0", "expected error to contain version string") } func TestGetTagMatchingVersionOrConstraint_SkipsNonSemverTags(t *testing.T) { tags := []string{"alpha", "1.0.0", "beta", "1.1.0"} got, err := GetTagMatchingVersionOrConstraint(tags, ">=1.0.0 <2.0.0") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.0.0" { - t.Fatalf("expected '1.0.0', got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.0.0", got) } func TestGetTagMatchingVersionOrConstraint_OrderMatters_FirstMatchReturned(t *testing.T) { // Both 1.2.0 and 1.3.0 satisfy >=1.2.0 <2.0.0, but the function returns the first in input order tags := []string{"1.3.0", "1.2.0"} got, err := GetTagMatchingVersionOrConstraint(tags, ">=1.2.0 <2.0.0") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.3.0" { - t.Fatalf("expected '1.3.0' (first satisfying tag), got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.3.0", got, "first satisfying tag") } func TestGetTagMatchingVersionOrConstraint_ExactMatchHasPrecedence(t *testing.T) { // Exact match should be returned even if another earlier tag would match the parsed constraint tags := []string{"1.3.0", "1.2.3"} got, err := GetTagMatchingVersionOrConstraint(tags, "1.2.3") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if got != "1.2.3" { - t.Fatalf("expected exact match '1.2.3', got %q", got) - } + require.NoError(t, err) + require.Equal(t, "1.2.3", got, "expected exact match") } diff --git a/pkg/registry/transport_test.go b/pkg/registry/transport_test.go index b4990c526..e72c97c0d 100644 --- a/pkg/registry/transport_test.go +++ b/pkg/registry/transport_test.go @@ -22,6 +22,9 @@ import ( "io" "net/http" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var errMockRead = errors.New("mock read error") @@ -127,9 +130,7 @@ func Test_isPrintableContentType(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := isPrintableContentType(tt.contentType); got != tt.want { - t.Errorf("isPrintableContentType() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, isPrintableContentType(tt.contentType)) }) } } @@ -292,21 +293,13 @@ func Test_logResponseBody(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := logResponseBody(tt.resp); got != tt.want { - t.Errorf("logResponseBody() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, logResponseBody(tt.resp)) // validate the response body if tt.resp.Body != nil { readBytes, err := io.ReadAll(tt.resp.Body) - if err != nil { - t.Errorf("failed to read body after logResponseBody(), err= %v", err) - } - if !bytes.Equal(readBytes, tt.wantData) { - t.Errorf("resp.Body after logResponseBody() = %v, want %v", readBytes, tt.wantData) - } - if closeErr := tt.resp.Body.Close(); closeErr != nil { - t.Errorf("failed to close body after logResponseBody(), err= %v", closeErr) - } + require.NoError(t, err, "failed to read body after logResponseBody()") + assert.True(t, bytes.Equal(tt.wantData, readBytes), "resp.Body after logResponseBody()") + assert.NoError(t, tt.resp.Body.Close(), "failed to close body after logResponseBody()") } }) } @@ -331,12 +324,8 @@ func Test_logResponseBody_error(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := logResponseBody(tt.resp); got != tt.want { - t.Errorf("logResponseBody() = %v, want %v", got, tt.want) - } - if closeErr := tt.resp.Body.Close(); closeErr != nil { - t.Errorf("failed to close body after logResponseBody(), err= %v", closeErr) - } + assert.Equal(t, tt.want, logResponseBody(tt.resp)) + assert.NoError(t, tt.resp.Body.Close(), "failed to close body after logResponseBody()") }) } } @@ -391,9 +380,7 @@ func Test_containsCredentials(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := containsCredentials(tt.body); got != tt.want { - t.Errorf("containsCredentials() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, containsCredentials(tt.body)) }) } } From 4cce0e9e2a870508864c1d497918e201dc0f339c Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 17 Jun 2026 21:32:52 +1200 Subject: [PATCH 009/161] refactor(pkg/release): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- pkg/release/v1/util/filter_test.go | 29 ++++++---------- pkg/release/v1/util/kind_sorter_test.go | 35 ++++++------------- pkg/release/v1/util/manifest_sorter_test.go | 38 ++++++--------------- pkg/release/v1/util/manifest_test.go | 6 ++-- pkg/release/v1/util/sorter_test.go | 6 ++-- 5 files changed, 38 insertions(+), 76 deletions(-) diff --git a/pkg/release/v1/util/filter_test.go b/pkg/release/v1/util/filter_test.go index 1004a4c57..d6bda8f84 100644 --- a/pkg/release/v1/util/filter_test.go +++ b/pkg/release/v1/util/filter_test.go @@ -19,23 +19,19 @@ package util // import "helm.sh/helm/v4/pkg/release/v1/util" import ( "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/release/common" rspb "helm.sh/helm/v4/pkg/release/v1" ) func TestFilterAny(t *testing.T) { ls := Any(StatusFilter(common.StatusUninstalled)).Filter(releases) - if len(ls) != 2 { - t.Fatalf("expected 2 results, got '%d'", len(ls)) - } + require.Len(t, ls, 2) r0, r1 := ls[0], ls[1] - switch { - case r0.Info.Status != common.StatusUninstalled: - t.Fatalf("expected UNINSTALLED result, got '%s'", r1.Info.Status.String()) - case r1.Info.Status != common.StatusUninstalled: - t.Fatalf("expected UNINSTALLED result, got '%s'", r1.Info.Status.String()) - } + require.Equal(t, common.StatusUninstalled, r0.Info.Status) + require.Equal(t, common.StatusUninstalled, r1.Info.Status) } func TestFilterAll(t *testing.T) { @@ -47,14 +43,9 @@ func TestFilterAll(t *testing.T) { }) ls := All(fn).Filter(releases) - if len(ls) != 1 { - t.Fatalf("expected 1 result, got '%d'", len(ls)) - } - - switch r0 := ls[0]; { - case r0.Version == 4: - t.Fatal("got release with status revision 4") - case r0.Info.Status == common.StatusUninstalled: - t.Fatal("got release with status UNINSTALLED") - } + require.Len(t, ls, 1) + + r0 := ls[0] + require.NotEqual(t, 4, r0.Version, "got release with status revision 4") + require.NotEqual(t, common.StatusUninstalled, r0.Info.Status, "got release with status UNINSTALLED") } diff --git a/pkg/release/v1/util/kind_sorter_test.go b/pkg/release/v1/util/kind_sorter_test.go index 919de24e5..793ef87fe 100644 --- a/pkg/release/v1/util/kind_sorter_test.go +++ b/pkg/release/v1/util/kind_sorter_test.go @@ -20,6 +20,9 @@ import ( "bytes" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + release "helm.sh/helm/v4/pkg/release/v1" ) @@ -193,21 +196,15 @@ func TestKindSorter(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - if got, want := len(test.expected), len(manifests); got != want { - t.Fatalf("Expected %d names in order, got %d", want, got) - } + require.Equal(t, len(manifests), len(test.expected), "Expected %d names in order", len(manifests)) defer buf.Reset() orig := manifests for _, r := range sortManifestsByKind(manifests, test.order) { buf.WriteString(r.Name) } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) - } + assert.Equal(t, test.expected, buf.String()) for i, manifest := range orig { - if manifest != manifests[i] { - t.Fatal("Expected input to sortManifestsByKind to stay the same") - } + require.Equal(t, manifest, manifests[i], "Expected input to sortManifestsByKind to stay the same") } }) } @@ -267,9 +264,7 @@ func TestKindSorterKeepOriginalOrder(t *testing.T) { for _, r := range sortManifestsByKind(manifests, test.order) { buf.WriteString(r.Name) } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) - } + assert.Equal(t, test.expected, buf.String()) }) } } @@ -289,9 +284,7 @@ func TestKindSorterNamespaceAgainstUnknown(t *testing.T) { expectedOrder := []Manifest{namespace, unknown} for i, manifest := range manifests { - if expectedOrder[i].Name != manifest.Name { - t.Errorf("Expected %s, got %s", expectedOrder[i].Name, manifest.Name) - } + assert.Equal(t, expectedOrder[i].Name, manifest.Name) } } @@ -326,22 +319,16 @@ func TestKindSorterForHooks(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - if got, want := len(test.expected), len(hooks); got != want { - t.Fatalf("Expected %d names in order, got %d", want, got) - } + require.Equal(t, len(hooks), len(test.expected), "Expected %d names in order", len(hooks)) defer buf.Reset() orig := hooks for _, r := range sortHooksByKind(hooks, test.order) { buf.WriteString(r.Name) } for i, hook := range orig { - if hook != hooks[i] { - t.Fatal("Expected input to sortHooksByKind to stay the same") - } - } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) + require.Equal(t, hook, hooks[i], "Expected input to sortHooksByKind to stay the same") } + assert.Equal(t, test.expected, buf.String()) }) } } diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index baa320be0..2cdb55dc3 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -20,6 +20,8 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" release "helm.sh/helm/v4/pkg/release/v1" @@ -138,55 +140,39 @@ metadata: } hs, generic, err := SortManifests(manifests, nil, InstallOrder) - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } + require.NoError(t, err) // This test will fail if 'six' or 'seven' was added. - if len(generic) != 2 { - t.Errorf("Expected 2 generic manifests, got %d", len(generic)) - } + assert.Len(t, generic, 2) - if len(hs) != 4 { - t.Errorf("Expected 4 hooks, got %d", len(hs)) - } + assert.Len(t, hs, 4) for _, out := range hs { found := false for _, expect := range data { if out.Path == expect.path { found = true - if out.Path != expect.path { - t.Errorf("Expected path %s, got %s", expect.path, out.Path) - } + assert.Equal(t, expect.path, out.Path) nameFound := false for _, expectedName := range expect.name { if out.Name == expectedName { nameFound = true } } - if !nameFound { - t.Errorf("Got unexpected name %s", out.Name) - } + assert.True(t, nameFound, "Got unexpected name %s", out.Name) kindFound := false for _, expectedKind := range expect.kind { if out.Kind == expectedKind { kindFound = true } } - if !kindFound { - t.Errorf("Got unexpected kind %s", out.Kind) - } + assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) expectedHooks := expect.hooks[out.Name] - if !reflect.DeepEqual(expectedHooks, out.Events) { - t.Errorf("expected events: %v but got: %v", expectedHooks, out.Events) - } + assert.True(t, reflect.DeepEqual(expectedHooks, out.Events), "expected events: %v but got: %v", expectedHooks, out.Events) } } - if !found { - t.Errorf("Result not found: %v", out) - } + assert.True(t, found, "Result not found: %v", out) } // Verify the sort order @@ -218,8 +204,6 @@ metadata: sorted = sortManifestsByKind(sorted, InstallOrder) for i, m := range generic { - if m.Content != sorted[i].Content { - t.Errorf("Expected %q, got %q", m.Content, sorted[i].Content) - } + assert.Equal(t, sorted[i].Content, m.Content) } } diff --git a/pkg/release/v1/util/manifest_test.go b/pkg/release/v1/util/manifest_test.go index 516ac42d7..6bcf902d7 100644 --- a/pkg/release/v1/util/manifest_test.go +++ b/pkg/release/v1/util/manifest_test.go @@ -19,6 +19,8 @@ package util // import "helm.sh/helm/v4/pkg/release/v1/util" import ( "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestSplitManifests(t *testing.T) { @@ -509,9 +511,7 @@ metadata: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := SplitManifests(tt.input) - if !reflect.DeepEqual(result, tt.expected) { - t.Errorf("SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) - } + assert.True(t, reflect.DeepEqual(result, tt.expected), "SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) }) } } diff --git a/pkg/release/v1/util/sorter_test.go b/pkg/release/v1/util/sorter_test.go index f47db7db8..0450b09e6 100644 --- a/pkg/release/v1/util/sorter_test.go +++ b/pkg/release/v1/util/sorter_test.go @@ -20,6 +20,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/pkg/release/common" rspb "helm.sh/helm/v4/pkg/release/v1" ) @@ -45,9 +47,7 @@ func tsRelease(name string, vers int, dur time.Duration, status common.Status) * func check(t *testing.T, by string, fn func(int, int) bool) { t.Helper() for i := len(releases) - 1; i > 0; i-- { - if fn(i, i-1) { - t.Errorf("release at positions '(%d,%d)' not sorted by %s", i-1, i, by) - } + assert.False(t, fn(i, i-1), "release at positions '(%d,%d)' not sorted by %s", i-1, i, by) } } From 7ab295fcfcf3977599939d76ffbf7a266401bfbc Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 17 Jun 2026 21:48:26 +1200 Subject: [PATCH 010/161] refactor(internal/release): convert tests to testify assert/require Replace native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) with github.com/stretchr/testify equivalents (assert.X, require.X) for improved test readability and error messages. Signed-off-by: George Jenkins --- internal/release/v2/util/filter_test.go | 29 +++++--------- internal/release/v2/util/kind_sorter_test.go | 35 ++++++----------- .../release/v2/util/manifest_sorter_test.go | 39 ++++++------------- internal/release/v2/util/manifest_test.go | 7 ++-- internal/release/v2/util/sorter_test.go | 6 +-- pkg/release/v1/util/kind_sorter_test.go | 4 +- pkg/release/v1/util/manifest_sorter_test.go | 5 +-- pkg/release/v1/util/manifest_test.go | 3 +- 8 files changed, 43 insertions(+), 85 deletions(-) diff --git a/internal/release/v2/util/filter_test.go b/internal/release/v2/util/filter_test.go index 35236498a..8c7363b87 100644 --- a/internal/release/v2/util/filter_test.go +++ b/internal/release/v2/util/filter_test.go @@ -19,23 +19,19 @@ package util // import "helm.sh/helm/v4/internal/release/v2/util" import ( "testing" + "github.com/stretchr/testify/require" + rspb "helm.sh/helm/v4/internal/release/v2" "helm.sh/helm/v4/pkg/release/common" ) func TestFilterAny(t *testing.T) { ls := Any(StatusFilter(common.StatusUninstalled)).Filter(releases) - if len(ls) != 2 { - t.Fatalf("expected 2 results, got '%d'", len(ls)) - } + require.Len(t, ls, 2) r0, r1 := ls[0], ls[1] - switch { - case r0.Info.Status != common.StatusUninstalled: - t.Fatalf("expected UNINSTALLED result, got '%s'", r1.Info.Status.String()) - case r1.Info.Status != common.StatusUninstalled: - t.Fatalf("expected UNINSTALLED result, got '%s'", r1.Info.Status.String()) - } + require.Equal(t, common.StatusUninstalled, r0.Info.Status) + require.Equal(t, common.StatusUninstalled, r1.Info.Status) } func TestFilterAll(t *testing.T) { @@ -47,14 +43,9 @@ func TestFilterAll(t *testing.T) { }) ls := All(fn).Filter(releases) - if len(ls) != 1 { - t.Fatalf("expected 1 result, got '%d'", len(ls)) - } - - switch r0 := ls[0]; { - case r0.Version == 4: - t.Fatal("got release with status revision 4") - case r0.Info.Status == common.StatusUninstalled: - t.Fatal("got release with status UNINSTALLED") - } + require.Len(t, ls, 1) + + r0 := ls[0] + require.NotEqual(t, 4, r0.Version, "got release with status revision 4") + require.NotEqual(t, common.StatusUninstalled, r0.Info.Status, "got release with status UNINSTALLED") } diff --git a/internal/release/v2/util/kind_sorter_test.go b/internal/release/v2/util/kind_sorter_test.go index 06418a5fc..dba19e287 100644 --- a/internal/release/v2/util/kind_sorter_test.go +++ b/internal/release/v2/util/kind_sorter_test.go @@ -20,6 +20,9 @@ import ( "bytes" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + release "helm.sh/helm/v4/internal/release/v2" ) @@ -193,21 +196,15 @@ func TestKindSorter(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - if got, want := len(test.expected), len(manifests); got != want { - t.Fatalf("Expected %d names in order, got %d", want, got) - } + require.Len(t, manifests, len(test.expected), "Expected %d names in order", len(manifests)) defer buf.Reset() orig := manifests for _, r := range sortManifestsByKind(manifests, test.order) { buf.WriteString(r.Name) } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) - } + assert.Equal(t, test.expected, buf.String()) for i, manifest := range orig { - if manifest != manifests[i] { - t.Fatal("Expected input to sortManifestsByKind to stay the same") - } + require.Equal(t, manifest, manifests[i], "Expected input to sortManifestsByKind to stay the same") } }) } @@ -267,9 +264,7 @@ func TestKindSorterKeepOriginalOrder(t *testing.T) { for _, r := range sortManifestsByKind(manifests, test.order) { buf.WriteString(r.Name) } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) - } + assert.Equal(t, test.expected, buf.String()) }) } } @@ -289,9 +284,7 @@ func TestKindSorterNamespaceAgainstUnknown(t *testing.T) { expectedOrder := []Manifest{namespace, unknown} for i, manifest := range manifests { - if expectedOrder[i].Name != manifest.Name { - t.Errorf("Expected %s, got %s", expectedOrder[i].Name, manifest.Name) - } + assert.Equal(t, expectedOrder[i].Name, manifest.Name) } } @@ -326,22 +319,16 @@ func TestKindSorterForHooks(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - if got, want := len(test.expected), len(hooks); got != want { - t.Fatalf("Expected %d names in order, got %d", want, got) - } + require.Len(t, hooks, len(test.expected), "Expected %d names in order", len(hooks)) defer buf.Reset() orig := hooks for _, r := range sortHooksByKind(hooks, test.order) { buf.WriteString(r.Name) } for i, hook := range orig { - if hook != hooks[i] { - t.Fatal("Expected input to sortHooksByKind to stay the same") - } - } - if got := buf.String(); got != test.expected { - t.Errorf("Expected %q, got %q", test.expected, got) + require.Equal(t, hook, hooks[i], "Expected input to sortHooksByKind to stay the same") } + assert.Equal(t, test.expected, buf.String()) }) } } diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index c8851d678..1c932d70c 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -17,9 +17,10 @@ limitations under the License. package util // import "helm.sh/helm/v4/internal/release/v2/util" import ( - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" release "helm.sh/helm/v4/internal/release/v2" @@ -138,55 +139,39 @@ metadata: } hs, generic, err := SortManifests(manifests, nil, InstallOrder) - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } + require.NoError(t, err) // This test will fail if 'six' or 'seven' was added. - if len(generic) != 2 { - t.Errorf("Expected 2 generic manifests, got %d", len(generic)) - } + assert.Len(t, generic, 2) - if len(hs) != 4 { - t.Errorf("Expected 4 hooks, got %d", len(hs)) - } + assert.Len(t, hs, 4) for _, out := range hs { found := false for _, expect := range data { if out.Path == expect.path { found = true - if out.Path != expect.path { - t.Errorf("Expected path %s, got %s", expect.path, out.Path) - } + assert.Equal(t, expect.path, out.Path) nameFound := false for _, expectedName := range expect.name { if out.Name == expectedName { nameFound = true } } - if !nameFound { - t.Errorf("Got unexpected name %s", out.Name) - } + assert.True(t, nameFound, "Got unexpected name %s", out.Name) kindFound := false for _, expectedKind := range expect.kind { if out.Kind == expectedKind { kindFound = true } } - if !kindFound { - t.Errorf("Got unexpected kind %s", out.Kind) - } + assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) expectedHooks := expect.hooks[out.Name] - if !reflect.DeepEqual(expectedHooks, out.Events) { - t.Errorf("expected events: %v but got: %v", expectedHooks, out.Events) - } + assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } } - if !found { - t.Errorf("Result not found: %v", out) - } + assert.True(t, found, "Result not found: %v", out) } // Verify the sort order @@ -218,8 +203,6 @@ metadata: sorted = sortManifestsByKind(sorted, InstallOrder) for i, m := range generic { - if m.Content != sorted[i].Content { - t.Errorf("Expected %q, got %q", m.Content, sorted[i].Content) - } + assert.Equal(t, m.Content, sorted[i].Content) } } diff --git a/internal/release/v2/util/manifest_test.go b/internal/release/v2/util/manifest_test.go index 72b095390..463ab5a4d 100644 --- a/internal/release/v2/util/manifest_test.go +++ b/internal/release/v2/util/manifest_test.go @@ -17,8 +17,9 @@ limitations under the License. package util // import "helm.sh/helm/v4/internal/release/v2/util" import ( - "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestSplitManifests(t *testing.T) { @@ -509,9 +510,7 @@ metadata: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := SplitManifests(tt.input) - if !reflect.DeepEqual(result, tt.expected) { - t.Errorf("SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) - } + assert.Equal(t, tt.expected, result, "SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) }) } } diff --git a/internal/release/v2/util/sorter_test.go b/internal/release/v2/util/sorter_test.go index 6cb876f69..82a53ae66 100644 --- a/internal/release/v2/util/sorter_test.go +++ b/internal/release/v2/util/sorter_test.go @@ -20,6 +20,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + rspb "helm.sh/helm/v4/internal/release/v2" "helm.sh/helm/v4/pkg/release/common" ) @@ -45,9 +47,7 @@ func tsRelease(name string, vers int, dur time.Duration, status common.Status) * func check(t *testing.T, by string, fn func(int, int) bool) { t.Helper() for i := len(releases) - 1; i > 0; i-- { - if fn(i, i-1) { - t.Errorf("release at positions '(%d,%d)' not sorted by %s", i-1, i, by) - } + assert.False(t, fn(i, i-1), "release at positions '(%d,%d)' not sorted by %s", i-1, i, by) } } diff --git a/pkg/release/v1/util/kind_sorter_test.go b/pkg/release/v1/util/kind_sorter_test.go index 793ef87fe..de8a79b25 100644 --- a/pkg/release/v1/util/kind_sorter_test.go +++ b/pkg/release/v1/util/kind_sorter_test.go @@ -196,7 +196,7 @@ func TestKindSorter(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - require.Equal(t, len(manifests), len(test.expected), "Expected %d names in order", len(manifests)) + require.Len(t, manifests, len(test.expected), "Expected %d names in order", len(manifests)) defer buf.Reset() orig := manifests for _, r := range sortManifestsByKind(manifests, test.order) { @@ -319,7 +319,7 @@ func TestKindSorterForHooks(t *testing.T) { } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { - require.Equal(t, len(hooks), len(test.expected), "Expected %d names in order", len(hooks)) + require.Len(t, hooks, len(test.expected), "Expected %d names in order", len(hooks)) defer buf.Reset() orig := hooks for _, r := range sortHooksByKind(hooks, test.order) { diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index 2cdb55dc3..b02400938 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -17,7 +17,6 @@ limitations under the License. package util import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -169,7 +168,7 @@ metadata: assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) expectedHooks := expect.hooks[out.Name] - assert.True(t, reflect.DeepEqual(expectedHooks, out.Events), "expected events: %v but got: %v", expectedHooks, out.Events) + assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } } assert.True(t, found, "Result not found: %v", out) @@ -204,6 +203,6 @@ metadata: sorted = sortManifestsByKind(sorted, InstallOrder) for i, m := range generic { - assert.Equal(t, sorted[i].Content, m.Content) + assert.Equal(t, m.Content, sorted[i].Content) } } diff --git a/pkg/release/v1/util/manifest_test.go b/pkg/release/v1/util/manifest_test.go index 6bcf902d7..d1efa21e1 100644 --- a/pkg/release/v1/util/manifest_test.go +++ b/pkg/release/v1/util/manifest_test.go @@ -17,7 +17,6 @@ limitations under the License. package util // import "helm.sh/helm/v4/pkg/release/v1/util" import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -511,7 +510,7 @@ metadata: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := SplitManifests(tt.input) - assert.True(t, reflect.DeepEqual(result, tt.expected), "SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) + assert.Equal(t, tt.expected, result, "SplitManifests() =\n%v\nwant:\n%v", result, tt.expected) }) } } From addbab2e6444954eb1a9bde86730ee7d11810b46 Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Tue, 16 Jun 2026 15:49:51 +1200 Subject: [PATCH 011/161] refactor(internal): convert tests to testify assert/require Convert internal/urlutil, internal/cli/output, internal/monocular, and internal/sympath test files from native Go testing patterns (t.Errorf, t.Fatalf, t.Error, t.Fatal) to github.com/stretchr/testify equivalents (assert.X, require.X). Signed-off-by: George Jenkins --- internal/cli/output/color_test.go | 18 +++++++---------- internal/monocular/client_test.go | 11 +++++------ internal/monocular/search_test.go | 15 ++++++--------- internal/sympath/walk_test.go | 32 +++++++++++-------------------- internal/urlutil/urlutil_test.go | 23 +++++++++++----------- 5 files changed, 40 insertions(+), 59 deletions(-) diff --git a/internal/cli/output/color_test.go b/internal/cli/output/color_test.go index f0484fc3a..807086c62 100644 --- a/internal/cli/output/color_test.go +++ b/internal/cli/output/color_test.go @@ -20,6 +20,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/pkg/release/common" ) @@ -93,14 +95,12 @@ func TestColorizeStatus(t *testing.T) { // In test environment, term.IsTerminal will be false, so we won't get color // unless we're testing the logic without terminal detection - if hasColor && !tt.wantColor { - t.Errorf("ColorizeStatus() returned color when none expected: %q", result) + if hasColor { + assert.True(t, tt.wantColor, "ColorizeStatus() returned color when none expected: %q", result) } // Always check the status text is present - if !strings.Contains(result, tt.status.String()) { - t.Errorf("ColorizeStatus() = %q, want to contain %q", result, tt.status.String()) - } + assert.Contains(t, result, tt.status.String()) }) } } @@ -139,9 +139,7 @@ func TestColorizeHeader(t *testing.T) { result := ColorizeHeader(tt.header, tt.noColor) // Always check the header text is present - if !strings.Contains(result, tt.header) { - t.Errorf("ColorizeHeader() = %q, want to contain %q", result, tt.header) - } + assert.Contains(t, result, tt.header) }) } } @@ -180,9 +178,7 @@ func TestColorizeNamespace(t *testing.T) { result := ColorizeNamespace(tt.namespace, tt.noColor) // Always check the namespace text is present - if !strings.Contains(result, tt.namespace) { - t.Errorf("ColorizeNamespace() = %q, want to contain %q", result, tt.namespace) - } + assert.Contains(t, result, tt.namespace) }) } } diff --git a/internal/monocular/client_test.go b/internal/monocular/client_test.go index abf914ef5..6456557d8 100644 --- a/internal/monocular/client_test.go +++ b/internal/monocular/client_test.go @@ -18,14 +18,13 @@ package monocular import ( "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNew(t *testing.T) { c, err := New("https://hub.helm.sh") - if err != nil { - t.Errorf("error creating client: %s", err) - } - if c.BaseURL != "https://hub.helm.sh" { - t.Errorf("incorrect BaseURL. Expected \"https://hub.helm.sh\" but got %q", c.BaseURL) - } + require.NoError(t, err) + assert.Equal(t, "https://hub.helm.sh", c.BaseURL) } diff --git a/internal/monocular/search_test.go b/internal/monocular/search_test.go index e4475f24e..85327cba7 100644 --- a/internal/monocular/search_test.go +++ b/internal/monocular/search_test.go @@ -21,6 +21,9 @@ import ( "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // A search response for phpmyadmin containing 2 results @@ -33,16 +36,10 @@ func TestSearch(t *testing.T) { defer ts.Close() c, err := New(ts.URL) - if err != nil { - t.Errorf("unable to create monocular client: %s", err) - } + require.NoError(t, err, "unable to create monocular client") results, err := c.SearchWithContext(t.Context(), "phpmyadmin") - if err != nil { - t.Errorf("unable to search monocular: %s", err) - } + require.NoError(t, err, "unable to search monocular") - if len(results) != 2 { - t.Error("Did not receive the expected number of results") - } + assert.Len(t, results, 2) } diff --git a/internal/sympath/walk_test.go b/internal/sympath/walk_test.go index 1eba8b996..b5bffbdab 100644 --- a/internal/sympath/walk_test.go +++ b/internal/sympath/walk_test.go @@ -24,6 +24,9 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type Node struct { @@ -80,21 +83,14 @@ func makeTree(t *testing.T) { walkTree(tree, tree.name, func(path string, n *Node) { if n.entries == nil { if n.symLinkedTo != "" { - if err := os.Symlink(n.symLinkedTo, path); err != nil { - t.Fatalf("makeTree: %v", err) - } + require.NoError(t, os.Symlink(n.symLinkedTo, path), "makeTree") } else { fd, err := os.Create(path) - if err != nil { - t.Fatalf("makeTree: %v", err) - return - } + require.NoError(t, err, "makeTree") fd.Close() } } else { - if err := os.Mkdir(path, 0770); err != nil { - t.Fatalf("makeTree: %v", err) - } + require.NoError(t, os.Mkdir(path, 0770), "makeTree") } }) } @@ -102,8 +98,8 @@ func makeTree(t *testing.T) { func checkMarks(t *testing.T, report bool) { t.Helper() walkTree(tree, tree.name, func(path string, n *Node) { - if n.marks != n.expectedMarks && report { - t.Errorf("node %s mark = %d; expected %d", path, n.marks, n.expectedMarks) + if report { + assert.Equal(t, n.expectedMarks, n.marks, "node %s", path) } n.marks = 0 }) @@ -137,16 +133,10 @@ func TestWalk(t *testing.T) { } // Expect no errors. err := Walk(tree.name, markFn) - if err != nil { - t.Fatalf("no error expected, found: %s", err) - } - if len(errors) != 0 { - t.Fatalf("unexpected errors: %s", errors) - } + require.NoError(t, err) + require.Empty(t, errors, "unexpected errors") checkMarks(t, true) // cleanup - if err := os.RemoveAll(tree.name); err != nil { - t.Errorf("removeTree: %v", err) - } + assert.NoError(t, os.RemoveAll(tree.name), "removeTree") } diff --git a/internal/urlutil/urlutil_test.go b/internal/urlutil/urlutil_test.go index 82acc40fe..d6b3f5256 100644 --- a/internal/urlutil/urlutil_test.go +++ b/internal/urlutil/urlutil_test.go @@ -16,7 +16,11 @@ limitations under the License. package urlutil -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestURLJoin(t *testing.T) { tests := []struct { @@ -31,11 +35,9 @@ func TestURLJoin(t *testing.T) { } for _, tt := range tests { - if got, err := URLJoin(tt.url, tt.paths...); err != nil { - t.Errorf("%s: error %q", tt.name, err) - } else if got != tt.expect { - t.Errorf("%s: expected %q, got %q", tt.name, tt.expect, got) - } + got, err := URLJoin(tt.url, tt.paths...) + assert.NoError(t, err, tt.name) + assert.Equal(t, tt.expect, got, tt.name) } } @@ -60,9 +62,7 @@ func TestEqual(t *testing.T) { {"%/1234", "%/123", false}, {"/1234", "%/1234", false}, } { - if tt.match != Equal(tt.a, tt.b) { - t.Errorf("Expected %q==%q to be %t", tt.a, tt.b, tt.match) - } + assert.Equal(t, tt.match, Equal(tt.a, tt.b), "Expected %q==%q to be %t", tt.a, tt.b, tt.match) } } @@ -74,8 +74,7 @@ func TestExtractHostname(t *testing.T) { "https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com", } for start, expect := range tests { - if got, _ := ExtractHostname(start); got != expect { - t.Errorf("Got %q, expected %q", got, expect) - } + got, _ := ExtractHostname(start) + assert.Equal(t, expect, got) } } From d887779b9b0eeb720672a7927479fc627e599c24 Mon Sep 17 00:00:00 2001 From: Will Noble Date: Fri, 27 Feb 2026 07:43:48 -0800 Subject: [PATCH 012/161] Properly format the extra field in gzipped packages Signed-off-by: Will Noble --- pkg/chart/v2/util/save.go | 2 +- pkg/chart/v2/util/save_test.go | 49 ++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/pkg/chart/v2/util/save.go b/pkg/chart/v2/util/save.go index e66d86991..09f57da32 100644 --- a/pkg/chart/v2/util/save.go +++ b/pkg/chart/v2/util/save.go @@ -33,7 +33,7 @@ import ( chart "helm.sh/helm/v4/pkg/chart/v2" ) -var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") +var headerBytes = []byte("rr(\x00aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") // SaveDir saves a chart as files in a directory. // diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index 2f2b73efd..aa562725e 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -130,6 +130,51 @@ func TestSave(t *testing.T) { } } +func TestSavedGzipExtraFieldIsValid(t *testing.T) { + tmp := t.TempDir() + c := &chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: chart.APIVersionV2, + Name: "ahab", + Version: "1.2.3", + }, + } + + where, err := Save(c, tmp) + if err != nil { + t.Fatalf("Failed to save: %s", err) + } + + f, err := os.Open(where) + if err != nil { + t.Fatalf("Failed to open saved file: %s", err) + } + defer f.Close() + + r, err := gzip.NewReader(f) + if err != nil { + t.Fatalf("Failed to create gzip reader: %s", err) + } + defer r.Close() + + // RFC 1952 §2.3.1.1: + // Each subfield consists of SI1, SI2 (1 byte each), + // a 2-byte little-endian LEN, and LEN bytes of data. + // https://www.rfc-editor.org/rfc/rfc1952.html#page-8 + // https://github.com/helm/helm/issues/31844 + extra := r.Extra + if len(extra) > 0 { + if len(extra) < 4 { + t.Fatalf("gzip extra field too short to contain a valid subfield: %d byte(s)", len(extra)) + } + dataLen := int(extra[2]) | int(extra[3])<<8 + // Assume a single subfield + if len(extra) != 4+dataLen { + t.Errorf("gzip extra field has malformed subfield: LEN=%d but %d data byte(s) follow the subfield header", dataLen, len(extra)-4) + } + } +} + // Creates a copy with a different schema; does not modify anything. func withSchema(chart chart.Chart, schema []byte) chart.Chart { chart.Schema = schema @@ -299,7 +344,7 @@ func TestRepeatableSave(t *testing.T) { Schema: []byte("{\n \"title\": \"Values\"\n}"), SchemaModTime: modTime, }, - want: "fea2662522317b65c2788ff9e5fc446a9264830038dac618d4449493d99b3257", + want: "63358874b93ea095c857cd66bcf5d0a4464840cf84a07547db744d81d6c5af59", }, { name: "Package 2 files", @@ -321,7 +366,7 @@ func TestRepeatableSave(t *testing.T) { Schema: []byte("{\n \"title\": \"Values\"\n}"), SchemaModTime: modTime, }, - want: "7ae92b2f274bb51ea3f1969e4187d78cc52b5f6f663b44b8fb3b40bcb8ee46f3", + want: "c2a43990053da788ad4e260d3b00d52a0b103ccc67ab9f48278a7b6dcfb2a4bd", }, } for _, test := range tests { From 61bba7c659e3b45ba4db195d58acc668a9c32441 Mon Sep 17 00:00:00 2001 From: Will Noble <4642422+ouillie@users.noreply.github.com> Date: Tue, 23 Jun 2026 00:43:51 +0200 Subject: [PATCH 013/161] Apply suggestions Co-authored-by: George Jenkins Signed-off-by: Will Noble <4642422+ouillie@users.noreply.github.com> --- pkg/chart/v2/util/save.go | 6 +++++- pkg/chart/v2/util/save_test.go | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pkg/chart/v2/util/save.go b/pkg/chart/v2/util/save.go index 09f57da32..19adb8d5f 100644 --- a/pkg/chart/v2/util/save.go +++ b/pkg/chart/v2/util/save.go @@ -33,7 +33,11 @@ import ( chart "helm.sh/helm/v4/pkg/chart/v2" ) -var headerBytes = []byte("rr(\x00aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") +// RFC 1952 subfield header: +// +---+---+---+---+==================================+ +// |SI1|SI2| LEN |... LEN bytes of subfield data ...| +// +---+---+---+---+==================================+ +var headerBytes = []byte("rr\x28\x00aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") // SaveDir saves a chart as files in a directory. // diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index aa562725e..d23f1e8ac 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -21,6 +21,7 @@ import ( "bytes" "compress/gzip" "crypto/sha256" + "encoding/binary" "encoding/hex" "errors" "io" @@ -35,6 +36,8 @@ import ( "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" + + "github.com/stretchr/testify/require" ) func TestSave(t *testing.T) { @@ -130,6 +133,7 @@ func TestSave(t *testing.T) { } } +// https://github.com/helm/helm/issues/31844 func TestSavedGzipExtraFieldIsValid(t *testing.T) { tmp := t.TempDir() c := &chart.Chart{ @@ -161,18 +165,14 @@ func TestSavedGzipExtraFieldIsValid(t *testing.T) { // Each subfield consists of SI1, SI2 (1 byte each), // a 2-byte little-endian LEN, and LEN bytes of data. // https://www.rfc-editor.org/rfc/rfc1952.html#page-8 - // https://github.com/helm/helm/issues/31844 extra := r.Extra - if len(extra) > 0 { - if len(extra) < 4 { - t.Fatalf("gzip extra field too short to contain a valid subfield: %d byte(s)", len(extra)) - } - dataLen := int(extra[2]) | int(extra[3])<<8 - // Assume a single subfield - if len(extra) != 4+dataLen { - t.Errorf("gzip extra field has malformed subfield: LEN=%d but %d data byte(s) follow the subfield header", dataLen, len(extra)-4) - } - } + + require.NotEmpty(t, extra) + require.GreaterOrEqual(t, len(extra), 4) + + dataLen := int(binary.LittleEndian.Uint16(extra[2:4])) + // Assume a single subfield. + require.Lenf(t, extra, 4+dataLen, "gzip extra field has malformed subfield: LEN=%d but %d data byte(s) follow the subfield header", dataLen, len(extra)-4) } // Creates a copy with a different schema; does not modify anything. From 07faec5593aabbde72c357d9c10123b6a3da33c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:32:37 +0000 Subject: [PATCH 014/161] chore(deps): bump actions/setup-go from 6.4.0 to 6.5.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.4.0 to 6.5.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/4a3601121dd01d1626a1e23e37211e3254c1c06c...924ae3a1cded613372ab5595356fb5720e22ba16) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-test.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/govulncheck.yml | 2 +- .github/workflows/release.yml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a0fea406c..b4ce89f26 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -22,7 +22,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # pin@6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 13ea569ef..e13d8950e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -17,7 +17,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # pin@6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index ba3714eae..93ab559fc 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -25,7 +25,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # pin@6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 993c45899..ee2612917 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # pin@6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true @@ -93,7 +93,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # pin@6.4.0 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true From 144246cd2893f92ee8e477c691837ea27e8c2733 Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Mon, 22 Jun 2026 19:31:18 -0700 Subject: [PATCH 015/161] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: George Jenkins --- pkg/cli/environment_test.go | 3 +-- pkg/cli/values/options_test.go | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index f1067f6c6..9303389a3 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -18,7 +18,6 @@ package cli import ( "os" - "reflect" "strings" "testing" @@ -137,7 +136,7 @@ func TestEnvSettings(t *testing.T) { assert.Equal(t, tt.kcontext, settings.KubeContext, "kube-context") assert.Equal(t, tt.maxhistory, settings.MaxHistory, "maxHistory") assert.Equal(t, tt.kubeAsUser, settings.KubeAsUser, "kubeAsUser") - assert.True(t, reflect.DeepEqual(tt.kubeAsGroups, settings.KubeAsGroups), "kubeAsGroups") + assert.Equal(t, tt.kubeAsGroups, settings.KubeAsGroups, "kubeAsGroups") assert.Equal(t, tt.kubeCaFile, settings.KubeCaFile, "kubeCaFile") assert.Equal(t, tt.burstLimit, settings.BurstLimit, "burstLimit") assert.Equal(t, tt.kubeInsecure, settings.KubeInsecureSkipTLSVerify, "kubeInsecure") diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index 3a33da7f1..f6a116f18 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -21,7 +21,6 @@ import ( "errors" "os" "path/filepath" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -214,7 +213,7 @@ func TestReadFile(t *testing.T) { // Test the function got, err := readFile(actualFilePath, tt.providers) - assert.NoError(t, err, "readFile() expected no error for stdin") + require.NoError(t, err, "readFile() expected no error for stdin") assert.Equal(t, testData, got) return } @@ -360,8 +359,8 @@ func TestMergeValuesCLI(t *testing.T) { assert.Error(t, err) return } - assert.NoError(t, err) - assert.True(t, reflect.DeepEqual(got, tt.expected), "MergeValues() = %v, want %v", got, tt.expected) + require.NoError(t, err) + assert.Equal(t, tt.expected, got) }) } } From f76136d39f8c1fd6110a23317786c4c53f6f9cb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:32:44 +0000 Subject: [PATCH 016/161] chore(deps): bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 9.2.1 to 9.3.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/82606bf257cbaff209d206a39f5134f0cfbfd2ee...ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: 9.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e13d8950e..6355db230 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -22,6 +22,6 @@ jobs: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true - name: golangci-lint - uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee #pin@9.2.1 + uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a #pin@9.3.0 with: version: ${{ env.GOLANGCI_LINT_VERSION }} From 5a9b8a788ff260c031f2d2f3e1b6903bd31b3496 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 21:33:40 +0000 Subject: [PATCH 017/161] chore(deps): bump github.com/fluxcd/cli-utils from 1.2.1 to 1.2.2 Bumps [github.com/fluxcd/cli-utils](https://github.com/fluxcd/cli-utils) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/fluxcd/cli-utils/releases) - [Commits](https://github.com/fluxcd/cli-utils/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: github.com/fluxcd/cli-utils dependency-version: 1.2.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ea6d6c972..d85d0387a 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/evanphx/json-patch/v5 v5.9.11 github.com/extism/go-sdk v1.7.1 github.com/fatih/color v1.19.0 - github.com/fluxcd/cli-utils v1.2.1 + github.com/fluxcd/cli-utils v1.2.2 github.com/foxcpp/go-mockdns v1.2.0 github.com/gobwas/glob v0.2.3 github.com/gofrs/flock v0.13.0 @@ -115,7 +115,7 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/gomega v1.39.1 // indirect + github.com/onsi/gomega v1.42.1 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect @@ -158,7 +158,7 @@ require ( go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/mod v0.36.0 // indirect - golang.org/x/net v0.55.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.21.0 // indirect golang.org/x/sys v0.46.0 // indirect @@ -173,7 +173,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/component-base v0.36.2 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect - k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/kustomize/api v0.21.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/go.sum b/go.sum index f50611b85..a92d35dfe 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/cli-utils v1.2.1 h1:ug9CicKW7H9QXnvNDapTSKuryZvWcu4Nw7pRvQa6jDY= -github.com/fluxcd/cli-utils v1.2.1/go.mod h1:cky6M6eHvTQkoPtsuFYLIgAMYdpTCSLoor4IA6vueSw= +github.com/fluxcd/cli-utils v1.2.2 h1:adDOmwE+LSwTzmYUaoEFPblruOuaQEKAg1ZNTmPJObE= +github.com/fluxcd/cli-utils v1.2.2/go.mod h1:FsghNGY+3Sr70c0FOB7I5So0kzoYVdvQ8GTid3XXVWM= github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0= github.com/foxcpp/go-mockdns v1.2.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -233,8 +233,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= -github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= -github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= +github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= +github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -400,8 +400,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -505,8 +505,8 @@ k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hk k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= k8s.io/kubectl v0.36.2 h1:rpUGGpeL09XVOLep2yle5jrtk//JA1L6ZHfkQQtVEwk= k8s.io/kubectl v0.36.2/go.mod h1:gVbQ3B/yb4bSR2ggQ7rd0W6icUSWs7sduH4e16Vii+0= -k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= -k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= +k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= oras.land/oras-go/v2 v2.6.1 h1:bonOEkjLfp8tt6qXWRRWP6p1F+9octchOf2EqnWB4Zs= oras.land/oras-go/v2 v2.6.1/go.mod h1:dhtFrFOuZuDtAVeZ9FUnaa5zfzplG3ZnFX9/uH1J/Yk= sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= From 301e3a12d55c279ef3bd0b1976bafd43bc1e0b7b Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Thu, 28 Aug 2025 14:43:49 +0900 Subject: [PATCH 018/161] fix scope when helm push to a registry that use token auth Signed-off-by: kimsungmin1 --- go.mod | 2 + go.sum | 4 + pkg/registry/client.go | 9 ++ pkg/registry/client_http_test.go | 2 +- pkg/registry/client_insecure_tls_test.go | 2 +- pkg/registry/client_scope_test.go | 109 +++++++++++++++++++++++ pkg/registry/client_tls_test.go | 2 +- pkg/registry/registry_test.go | 33 +++++-- 8 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 pkg/registry/client_scope_test.go diff --git a/go.mod b/go.mod index d85d0387a..cb512b54b 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/moby/term v0.5.2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/rubenv/sql-migrate v1.8.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/spf13/cobra v1.10.2 @@ -80,6 +81,7 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect diff --git a/go.sum b/go.sum index a92d35dfe..0c237ab46 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,8 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -241,6 +243,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 77f3d3efd..366251c60 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -717,6 +717,8 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu repository.PlainHTTP = c.plainHTTP repository.Client = c.authorizer + ctx = WithScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) + manifestDescriptor, err = oras.ExtendedCopy(ctx, memoryStore, parsedRef.String(), repository, parsedRef.String(), oras.DefaultExtendedCopyOptions) if err != nil { return nil, err @@ -927,3 +929,10 @@ func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, return oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, parsedRef.String()) } + +func WithScopeHint(ctx context.Context, target any, actions ...string) context.Context { + if repo, ok := target.(*remote.Repository); ok { + return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) + } + return ctx +} diff --git a/pkg/registry/client_http_test.go b/pkg/registry/client_http_test.go index 3eb74c541..316a82d3f 100644 --- a/pkg/registry/client_http_test.go +++ b/pkg/registry/client_http_test.go @@ -30,7 +30,7 @@ type HTTPRegistryClientTestSuite struct { func (suite *HTTPRegistryClientTestSuite) SetupSuite() { // init test client - setup(&suite.TestRegistry, false, false) + setup(&suite.TestRegistry, false, false, "htpasswd") } func (suite *HTTPRegistryClientTestSuite) TearDownSuite() { diff --git a/pkg/registry/client_insecure_tls_test.go b/pkg/registry/client_insecure_tls_test.go index 8c4e928e4..ae0a44337 100644 --- a/pkg/registry/client_insecure_tls_test.go +++ b/pkg/registry/client_insecure_tls_test.go @@ -29,7 +29,7 @@ type InsecureTLSRegistryClientTestSuite struct { func (suite *InsecureTLSRegistryClientTestSuite) SetupSuite() { // init test client - setup(&suite.TestRegistry, true, true) + setup(&suite.TestRegistry, true, true, "htpasswd") } func (suite *InsecureTLSRegistryClientTestSuite) TearDownSuite() { diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go new file mode 100644 index 000000000..245af5e3e --- /dev/null +++ b/pkg/registry/client_scope_test.go @@ -0,0 +1,109 @@ +/* +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 registry + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "testing" + + "github.com/stretchr/testify/suite" +) + +type RegistryScopeTestSuite struct { + TestSuite +} + +func (suite *RegistryScopeTestSuite) SetupSuite() { + // set registry use token auth + dockerRegistry := setup(&suite.TestSuite, true, true, "token") + // Start Docker registry + go dockerRegistry.ListenAndServe() +} +func (suite *RegistryScopeTestSuite) TearDownSuite() { + teardown(&suite.TestSuite) + os.RemoveAll(suite.WorkspaceDir) +} + +func (suite *RegistryScopeTestSuite) Test_1_Cehck_Push_Request_Scope() { + + //set simple auth server to check the auth request scope + server := &http.Server{ + Addr: suite.AuthServerHost, + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice"), r.URL.String()) + w.WriteHeader(http.StatusOK) + }), + } + go func() { + err := server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + log.Fatalf("http server failed to ListenAndServe:%v", err) + } + }() + + // basic push, good ref + testingChartCreationTime := "1977-09-02T22:04:05Z" + chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") + suite.Nil(err, "no error loading test chart") + meta, err := extractChartMeta(chartData) + suite.Nil(err, "no error extracting chart meta") + ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) + _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) + suite.NotNil(err, "error pushing good ref because auth server don't give proper token") + + //shutdown auth server + err = server.Shutdown(context.Background()) + suite.Nil(err, "shutdown simple auth server") + +} + +func (suite *RegistryScopeTestSuite) Test_2_Cehck_Pull_Request_Scope() { + + //set simple auth server to check the auth request scope + server := &http.Server{ + Addr: suite.AuthServerHost, + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice"), r.URL.String()) + w.WriteHeader(http.StatusOK) + }), + } + go func() { + err := server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + log.Fatalf("http server failed to ListenAndServe:%v", err) + } + }() + + // Load test chart (to build ref pushed in previous test) + // Simple pull, chart only + chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") + suite.Nil(err, "no error loading test chart") + meta, err := extractChartMeta(chartData) + suite.Nil(err, "no error extracting chart meta") + ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) + _, err = suite.RegistryClient.Pull(ref) + suite.NotNil(err, "error pulling a simple chart because auth server don't give proper token") + + //shutdown auth server + err = server.Shutdown(context.Background()) + suite.Nil(err, "shutdown simple auth server") +} + +func TestRegistryScopeTestSuite(t *testing.T) { + suite.Run(t, new(RegistryScopeTestSuite)) +} diff --git a/pkg/registry/client_tls_test.go b/pkg/registry/client_tls_test.go index 2bea0377f..45eff232c 100644 --- a/pkg/registry/client_tls_test.go +++ b/pkg/registry/client_tls_test.go @@ -31,7 +31,7 @@ type TLSRegistryClientTestSuite struct { func (suite *TLSRegistryClientTestSuite) SetupSuite() { // init test client - setup(&suite.TestRegistry, true, false) + setup(&suite.TestRegistry, true, false, "htpasswd") } func (suite *TLSRegistryClientTestSuite) TearDownSuite() { diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index dc8118c6e..76d6fcb16 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -33,8 +33,10 @@ import ( "github.com/distribution/distribution/v3/configuration" "github.com/distribution/distribution/v3/registry" _ "github.com/distribution/distribution/v3/registry/auth/htpasswd" + _ "github.com/distribution/distribution/v3/registry/auth/token" _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/phayes/freeport" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "golang.org/x/crypto/bcrypt" @@ -55,6 +57,8 @@ var ( testHtpasswdFileBasename = "authtest.htpasswd" testUsername = "myuser" testPassword = "mypass" + testIssuer = "testissuer" + testService = "testservice" ) type TestRegistry struct { @@ -62,13 +66,14 @@ type TestRegistry struct { Out io.Writer FakeRegistryHost string DockerRegistryHost string + AuthServerHost string CompromisedRegistryHost string WorkspaceDir string RegistryClient *Client dockerRegistry *registry.Registry } -func setup(suite *TestRegistry, tlsEnabled, insecure bool) { +func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.WorkspaceDir = testWorkspaceDir err := os.RemoveAll(suite.WorkspaceDir) require.NoError(suite.T(), err, "no error removing test workspace dir") @@ -139,11 +144,27 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool) { config.HTTP.DrainTimeout = time.Duration(10) * time.Second config.Storage = map[string]configuration.Parameters{"inmemory": map[string]any{}} - config.Auth = configuration.Auth{ - "htpasswd": configuration.Parameters{ - "realm": "localhost", - "path": htpasswdPath, - }, + if auth == "token" { + port, err := freeport.GetFreePort() + suite.Nil(err, "no error finding free port for test auth server") + + suite.AuthServerHost = fmt.Sprintf("localhost:%d", port) + + config.Auth = configuration.Auth{ + "token": configuration.Parameters{ + "realm": "http://" + suite.AuthServerHost + "/auth", + "service": testService, + "issuer": testIssuer, + "rootcertbundle": tlsServerCert, + }, + } + } else { + config.Auth = configuration.Auth{ + "htpasswd": configuration.Parameters{ + "realm": "localhost", + "path": htpasswdPath, + }, + } } // config tls From 319e06cda30e706db541066d5fe07249b0ed656c Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Thu, 28 Aug 2025 14:53:14 +0900 Subject: [PATCH 019/161] add newline in license header Signed-off-by: kimsungmin1 --- pkg/registry/client_scope_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 245af5e3e..707e9eed6 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -1,9 +1,12 @@ /* 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. From fc743b2a1be47c69cc3bf58e0fdc023f8844f866 Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Fri, 29 Aug 2025 09:34:11 +0900 Subject: [PATCH 020/161] remove freeport dependency Signed-off-by: kimsungmin1 --- go.mod | 1 - go.sum | 2 -- pkg/registry/registry_test.go | 7 ++++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index cb512b54b..ca3d23bb2 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,6 @@ require ( github.com/moby/term v0.5.2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 - github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/rubenv/sql-migrate v1.8.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/spf13/cobra v1.10.2 diff --git a/go.sum b/go.sum index 0c237ab46..2d8184ab0 100644 --- a/go.sum +++ b/go.sum @@ -243,8 +243,6 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 76d6fcb16..5f745c8a1 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -36,7 +36,6 @@ import ( _ "github.com/distribution/distribution/v3/registry/auth/token" _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/phayes/freeport" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "golang.org/x/crypto/bcrypt" @@ -145,10 +144,12 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { config.Storage = map[string]configuration.Parameters{"inmemory": map[string]any{}} if auth == "token" { - port, err := freeport.GetFreePort() + ln, err := net.Listen("tcp", "127.0.0.1:0") suite.Nil(err, "no error finding free port for test auth server") + defer ln.Close() - suite.AuthServerHost = fmt.Sprintf("localhost:%d", port) + //set test auth server host + suite.AuthServerHost = ln.Addr().String() config.Auth = configuration.Auth{ "token": configuration.Parameters{ From 9d77ccd46ddf9b2675137891c159d1de35674072 Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Tue, 9 Sep 2025 10:00:54 +0900 Subject: [PATCH 021/161] fix typo Signed-off-by: kimsungmin1 --- pkg/registry/client_scope_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 707e9eed6..37c77d7d3 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -42,7 +42,7 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { os.RemoveAll(suite.WorkspaceDir) } -func (suite *RegistryScopeTestSuite) Test_1_Cehck_Push_Request_Scope() { +func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { //set simple auth server to check the auth request scope server := &http.Server{ @@ -75,7 +75,7 @@ func (suite *RegistryScopeTestSuite) Test_1_Cehck_Push_Request_Scope() { } -func (suite *RegistryScopeTestSuite) Test_2_Cehck_Pull_Request_Scope() { +func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { //set simple auth server to check the auth request scope server := &http.Server{ From 8c8d6e3262be77783ef42a47c9593b6e42a3066a Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Thu, 11 Dec 2025 00:49:09 +0900 Subject: [PATCH 022/161] change client_scope_test.go to use httptest Signed-off-by: kimsungmin1 --- pkg/registry/client_scope_test.go | 61 ++++++++++++------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 37c77d7d3..e5a34214e 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -17,10 +17,10 @@ limitations under the License. package registry import ( - "context" "fmt" - "log" + "net" "net/http" + "net/http/httptest" "os" "testing" @@ -44,20 +44,17 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { - //set simple auth server to check the auth request scope - server := &http.Server{ - Addr: suite.AuthServerHost, - Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice"), r.URL.String()) - w.WriteHeader(http.StatusOK) - }), - } - go func() { - err := server.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - log.Fatalf("http server failed to ListenAndServe:%v", err) - } - }() + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice"), r.URL.String()) + w.WriteHeader(http.StatusOK) + }) + listener, err := net.Listen("tcp", suite.AuthServerHost) + suite.Nil(err, "no error creating server listner") + + ts := httptest.NewUnstartedServer(handler) + ts.Listener = listener + ts.Start() + defer ts.Close() // basic push, good ref testingChartCreationTime := "1977-09-02T22:04:05Z" @@ -69,28 +66,21 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) suite.NotNil(err, "error pushing good ref because auth server don't give proper token") - //shutdown auth server - err = server.Shutdown(context.Background()) - suite.Nil(err, "shutdown simple auth server") - } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { - //set simple auth server to check the auth request scope - server := &http.Server{ - Addr: suite.AuthServerHost, - Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice"), r.URL.String()) - w.WriteHeader(http.StatusOK) - }), - } - go func() { - err := server.ListenAndServe() - if err != nil && err != http.ErrServerClosed { - log.Fatalf("http server failed to ListenAndServe:%v", err) - } - }() + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice"), r.URL.String()) + w.WriteHeader(http.StatusOK) + }) + listener, err := net.Listen("tcp", suite.AuthServerHost) + suite.Nil(err, "no error creating server listner") + + ts := httptest.NewUnstartedServer(handler) + ts.Listener = listener + ts.Start() + defer ts.Close() // Load test chart (to build ref pushed in previous test) // Simple pull, chart only @@ -102,9 +92,6 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { _, err = suite.RegistryClient.Pull(ref) suite.NotNil(err, "error pulling a simple chart because auth server don't give proper token") - //shutdown auth server - err = server.Shutdown(context.Background()) - suite.Nil(err, "shutdown simple auth server") } func TestRegistryScopeTestSuite(t *testing.T) { From 26e5071f6680272d773f0ca22ea946a35c4dce66 Mon Sep 17 00:00:00 2001 From: kimsungmin1 Date: Fri, 9 Jan 2026 20:10:24 +0900 Subject: [PATCH 023/161] change suite.Nil, suite.NotNill to more proper function(suite.NoError, suite.Error) Signed-off-by: kimsungmin1 --- pkg/registry/client_scope_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index e5a34214e..2039faad9 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -49,7 +49,7 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) - suite.Nil(err, "no error creating server listner") + suite.NoError(err, "no error creating server listner") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -59,12 +59,12 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { // basic push, good ref testingChartCreationTime := "1977-09-02T22:04:05Z" chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") - suite.Nil(err, "no error loading test chart") + suite.NoError(err, "no error loading test chart") meta, err := extractChartMeta(chartData) - suite.Nil(err, "no error extracting chart meta") + suite.NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) - suite.NotNil(err, "error pushing good ref because auth server don't give proper token") + suite.Error(err, "error pushing good ref because auth server don't give proper token") } @@ -75,7 +75,7 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) - suite.Nil(err, "no error creating server listner") + suite.NoError(err, "no error creating server listner") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -85,12 +85,12 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { // Load test chart (to build ref pushed in previous test) // Simple pull, chart only chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") - suite.Nil(err, "no error loading test chart") + suite.NoError(err, "no error loading test chart") meta, err := extractChartMeta(chartData) - suite.Nil(err, "no error extracting chart meta") + suite.NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Pull(ref) - suite.NotNil(err, "error pulling a simple chart because auth server don't give proper token") + suite.Error(err, "error pulling a simple chart because auth server don't give proper token") } From 530e728ea932109befc4a8165cd9a2bc78170c07 Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Wed, 11 Mar 2026 10:56:03 +0900 Subject: [PATCH 024/161] fix typo, remove unnecessary code, fix to avoid to use the assertion in http hanlder Signed-off-by: kimsm28 --- pkg/registry/client.go | 11 +++++++++-- pkg/registry/client_scope_test.go | 21 +++++++++++++++------ pkg/registry/registry_test.go | 1 - 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 366251c60..1fe4b7813 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -717,7 +717,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu repository.PlainHTTP = c.plainHTTP repository.Client = c.authorizer - ctx = WithScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) + ctx = withScopeHint(ctx, repository, auth.ActionPull, auth.ActionPush) manifestDescriptor, err = oras.ExtendedCopy(ctx, memoryStore, parsedRef.String(), repository, parsedRef.String(), oras.DefaultExtendedCopyOptions) if err != nil { @@ -930,7 +930,14 @@ func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, manifestData, parsedRef.String()) } -func WithScopeHint(ctx context.Context, target any, actions ...string) context.Context { +// add actions when request a registry authentication token(jwt) +// example1. when we want to pull 'testrepo/local-subchart' we can send bellow url, and 'pull' is the action +// auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice +// example2. when we want to push 'testrepo/local-subchart' we can send bellow url, and 'pull%2Cpush' are the actions +// auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice +// we can set the actions like bellow +// example) ctx = WithScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) +func withScopeHint(ctx context.Context, target any, actions ...string) context.Context { if repo, ok := target.(*remote.Repository); ok { return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) } diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 2039faad9..2a3def6f6 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -44,12 +44,14 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { + var requestUrl string + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice"), r.URL.String()) + requestUrl = r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) - suite.NoError(err, "no error creating server listner") + suite.NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -64,18 +66,23 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { suite.NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) - suite.Error(err, "error pushing good ref because auth server don't give proper token") + suite.Error(err, "error pushing good ref because auth server doesn't give proper token") + + //check the url that authentication server received + suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice", requestUrl) } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { + var requestUrl string + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - suite.Equal(string("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice"), r.URL.String()) + requestUrl = r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) - suite.NoError(err, "no error creating server listner") + suite.NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -90,8 +97,10 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { suite.NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Pull(ref) - suite.Error(err, "error pulling a simple chart because auth server don't give proper token") + suite.Error(err, "error pulling a simple chart because auth server doesn't give proper token") + //check the url that authentication server received + suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice", requestUrl) } func TestRegistryScopeTestSuite(t *testing.T) { diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 5f745c8a1..3dc65908a 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -146,7 +146,6 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { if auth == "token" { ln, err := net.Listen("tcp", "127.0.0.1:0") suite.Nil(err, "no error finding free port for test auth server") - defer ln.Close() //set test auth server host suite.AuthServerHost = ln.Addr().String() From 8883c9cc7006eef7e3d07836b2d5dd7ca1066168 Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Wed, 11 Mar 2026 11:03:34 +0900 Subject: [PATCH 025/161] fix variable naming requestUrl -> requestURL Signed-off-by: kimsm28 --- pkg/registry/client_scope_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 2a3def6f6..a5f8ea16c 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -44,10 +44,10 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { - var requestUrl string + var requestURL string handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestUrl = r.URL.String() + requestURL = r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) @@ -69,16 +69,16 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { suite.Error(err, "error pushing good ref because auth server doesn't give proper token") //check the url that authentication server received - suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice", requestUrl) + suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice", requestURL) } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { - var requestUrl string + var requestURL string handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestUrl = r.URL.String() + requestURL = r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) @@ -100,7 +100,7 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { suite.Error(err, "error pulling a simple chart because auth server doesn't give proper token") //check the url that authentication server received - suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice", requestUrl) + suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice", requestURL) } func TestRegistryScopeTestSuite(t *testing.T) { From 1f0a72849657c3fe167320f7f5729c377f6dadf8 Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Mon, 13 Apr 2026 13:15:49 +0900 Subject: [PATCH 026/161] fix registry test failures by adjusting DockerRegistryHost and auth server listener management - Change DockerRegistryHost to use 127.0.0.1 for HTTP tests and helm-test-registry for TLS tests to match certificate hostname - Add defer ln.Close() to prevent resource leak in token auth server setup - Restore requestURL variable and assertion in test body instead of handler to avoid potential race condition Signed-off-by: kimsm28 --- pkg/registry/client_scope_test.go | 3 --- pkg/registry/registry_test.go | 12 ++++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index a5f8ea16c..09ad2b0d0 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -45,7 +45,6 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { var requestURL string - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { requestURL = r.URL.String() w.WriteHeader(http.StatusOK) @@ -70,13 +69,11 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { //check the url that authentication server received suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice", requestURL) - } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { var requestURL string - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { requestURL = r.URL.String() w.WriteHeader(http.StatusOK) diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 3dc65908a..d00a9f3c6 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -133,11 +133,14 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.Require().NoError(err, "no error finding free port for test registry") defer func() { _ = ln.Close() }() - // Change the registry host to another host which is not localhost. - // This is required because Docker enforces HTTP if the registry - // host is localhost/127.0.0.1. + // Use localhost for HTTP tests and helm-test-registry for TLS tests. + // TLS tests need a different hostname to match the certificate. port := ln.Addr().(*net.TCPAddr).Port - suite.DockerRegistryHost = fmt.Sprintf("helm-test-registry:%d", port) + if tlsEnabled { + suite.DockerRegistryHost = fmt.Sprintf("helm-test-registry:%d", port) + } else { + suite.DockerRegistryHost = fmt.Sprintf("127.0.0.1:%d", port) + } config.HTTP.Addr = ln.Addr().String() config.HTTP.DrainTimeout = time.Duration(10) * time.Second @@ -146,6 +149,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { if auth == "token" { ln, err := net.Listen("tcp", "127.0.0.1:0") suite.Nil(err, "no error finding free port for test auth server") + defer ln.Close() //set test auth server host suite.AuthServerHost = ln.Addr().String() From ee181f4570550d61379bf59f2a69b993b74d49cf Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Mon, 13 Apr 2026 13:29:21 +0900 Subject: [PATCH 027/161] fix typos in withScopeHint function comment - Change 'bellow' to 'below' (spelling correction in multiple places) - Change 'WithScopeHint' to 'withScopeHint' to match actual function name Signed-off-by: kimsm28 --- pkg/registry/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 1fe4b7813..e252ad2c5 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -931,12 +931,12 @@ func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, } // add actions when request a registry authentication token(jwt) -// example1. when we want to pull 'testrepo/local-subchart' we can send bellow url, and 'pull' is the action +// example1. when we want to pull 'testrepo/local-subchart' we can send below url, and 'pull' is the action // auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice -// example2. when we want to push 'testrepo/local-subchart' we can send bellow url, and 'pull%2Cpush' are the actions +// example2. when we want to push 'testrepo/local-subchart' we can send below url, and 'pull%2Cpush' are the actions // auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice -// we can set the actions like bellow -// example) ctx = WithScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) +// we can set the actions like below +// example) ctx = withScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) func withScopeHint(ctx context.Context, target any, actions ...string) context.Context { if repo, ok := target.(*remote.Repository); ok { return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) From 9b7a70f0ca4bf0dcfd242962d9eef211188057dd Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Mon, 13 Apr 2026 17:53:48 +0900 Subject: [PATCH 028/161] test: improve client_scope_test.go to avoid data races and brittle assertions - Fix data race by using channel instead of shared variable for requestURL - Make assertions more robust by parsing URL and checking query parameters instead of exact string matching Signed-off-by: kimsm28 --- pkg/registry/client_scope_test.go | 36 +++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 09ad2b0d0..b1da20a6b 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -21,8 +21,10 @@ import ( "net" "net/http" "net/http/httptest" + "net/url" "os" "testing" + "time" "github.com/stretchr/testify/suite" ) @@ -44,9 +46,9 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { - var requestURL string + requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestURL = r.URL.String() + requestURL <- r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) @@ -68,14 +70,25 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { suite.Error(err, "error pushing good ref because auth server doesn't give proper token") //check the url that authentication server received - suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice", requestURL) + select { + case urlStr := <-requestURL: + u, err := url.Parse(urlStr) + suite.NoError(err, "no error parsing requested URL") + + suite.Equal("/auth", u.Path) + suite.Equal("testservice", u.Query().Get("service")) + scope := u.Query().Get("scope") + suite.Contains(scope, "repository:testrepo/local-subchart:pull,push") + case <-time.After(5 * time.Second): + suite.T().Fatal("timeout waiting for auth request") + } } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { - var requestURL string + requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestURL = r.URL.String() + requestURL <- r.URL.String() w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) @@ -97,7 +110,18 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { suite.Error(err, "error pulling a simple chart because auth server doesn't give proper token") //check the url that authentication server received - suite.Equal("/auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull&service=testservice", requestURL) + select { + case urlStr := <-requestURL: + u, err := url.Parse(urlStr) + suite.NoError(err, "no error parsing requested URL") + + suite.Equal("/auth", u.Path) + suite.Equal("testservice", u.Query().Get("service")) + scope := u.Query().Get("scope") + suite.Contains(scope, "repository:testrepo/local-subchart:pull") + case <-time.After(5 * time.Second): + suite.T().Fatal("timeout waiting for auth request") + } } func TestRegistryScopeTestSuite(t *testing.T) { From 26ada49c1ad50af5e11dbb8a65b703251295c689 Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Mon, 25 May 2026 08:45:09 -0600 Subject: [PATCH 029/161] Update pkg/registry/client.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Terry Howe --- pkg/registry/client.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pkg/registry/client.go b/pkg/registry/client.go index e252ad2c5..4d7da78dc 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -937,9 +937,6 @@ func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, // auth?scope=repository%3Atestrepo%2Flocal-subchart%3Apull%2Cpush&service=testservice // we can set the actions like below // example) ctx = withScopeHint(ctx, repository, auth.ActionPush, auth.ActionPull) -func withScopeHint(ctx context.Context, target any, actions ...string) context.Context { - if repo, ok := target.(*remote.Repository); ok { - return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) - } - return ctx +func withScopeHint(ctx context.Context, repo *remote.Repository, actions ...string) context.Context { + return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) } From 3cbee7e935eb6e783c36b17d6eb79eb6edcda15b Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Thu, 2 Jul 2026 21:49:33 +0900 Subject: [PATCH 030/161] fix(registry): use plain-http registry in token-auth scope test The scope test configured a TLS registry while advertising an http token realm. oras refuses to send credentials to an http token realm when the registry itself was contacted over https, so the auth server was never reached and the test timed out ("timeout waiting for auth request"). Use a plain-http registry so the registry and token-realm schemes match; the scope carried in the token request is what this test verifies, and that is independent of TLS. Also make the auth handler's channel send non-blocking so that a client retry can never block the handler and stall the push/pull flow, which addresses the review comment about a potential deadlock. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: kimsm28 --- pkg/registry/client_scope_test.go | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index b1da20a6b..98cdc74ff 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -30,17 +30,18 @@ import ( ) type RegistryScopeTestSuite struct { - TestSuite + TestRegistry } func (suite *RegistryScopeTestSuite) SetupSuite() { - // set registry use token auth - dockerRegistry := setup(&suite.TestSuite, true, true, "token") - // Start Docker registry - go dockerRegistry.ListenAndServe() + // Set up a plain-HTTP registry that uses token auth. The token realm is + // served over http (see setup), so the registry must be contacted over + // http as well: oras refuses to send credentials to an http token realm + // when the registry itself was reached over https. + setup(&suite.TestRegistry, false, false, "token") } func (suite *RegistryScopeTestSuite) TearDownSuite() { - teardown(&suite.TestSuite) + teardown(&suite.TestRegistry) os.RemoveAll(suite.WorkspaceDir) } @@ -48,7 +49,13 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestURL <- r.URL.String() + // Capture only the first auth request; never block the handler if the + // client happens to retry, so the auth server always responds and the + // push/pull flow can't deadlock waiting on us. + select { + case requestURL <- r.URL.String(): + default: + } w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) @@ -88,7 +95,13 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestURL <- r.URL.String() + // Capture only the first auth request; never block the handler if the + // client happens to retry, so the auth server always responds and the + // push/pull flow can't deadlock waiting on us. + select { + case requestURL <- r.URL.String(): + default: + } w.WriteHeader(http.StatusOK) }) listener, err := net.Listen("tcp", suite.AuthServerHost) From 4e9ca06856b1aeba65c4d4cd8e4dce4c83445776 Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Thu, 2 Jul 2026 21:49:33 +0900 Subject: [PATCH 031/161] chore: go mod tidy after rebase on main Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: kimsm28 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ca3d23bb2..628b3f374 100644 --- a/go.mod +++ b/go.mod @@ -80,7 +80,7 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect diff --git a/go.sum b/go.sum index 2d8184ab0..dc469fde9 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,8 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= From 503acff97580aa803f5d639fb1fbb06ad1226c31 Mon Sep 17 00:00:00 2001 From: kimsm28 Date: Thu, 2 Jul 2026 21:57:38 +0900 Subject: [PATCH 032/161] fix(registry): resolve golangci-lint issues in token-auth tests - Use (*net.ListenConfig).Listen with the test context instead of net.Listen (noctx). - Use suite.NoError instead of suite.Nil for the error check (testifylint). - Drop the unnecessary leading blank lines in the scope test funcs (whitespace). Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: kimsm28 --- pkg/registry/client_scope_test.go | 8 ++++---- pkg/registry/registry_test.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 98cdc74ff..f5f32ecb1 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -46,7 +46,6 @@ func (suite *RegistryScopeTestSuite) TearDownSuite() { } func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { - requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Capture only the first auth request; never block the handler if the @@ -58,7 +57,8 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { } w.WriteHeader(http.StatusOK) }) - listener, err := net.Listen("tcp", suite.AuthServerHost) + lnCfg := net.ListenConfig{} + listener, err := lnCfg.Listen(suite.T().Context(), "tcp", suite.AuthServerHost) suite.NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) @@ -92,7 +92,6 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { } func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { - requestURL := make(chan string, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Capture only the first auth request; never block the handler if the @@ -104,7 +103,8 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { } w.WriteHeader(http.StatusOK) }) - listener, err := net.Listen("tcp", suite.AuthServerHost) + lnCfg := net.ListenConfig{} + listener, err := lnCfg.Listen(suite.T().Context(), "tcp", suite.AuthServerHost) suite.NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index d00a9f3c6..9388c8142 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -147,8 +147,8 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { config.Storage = map[string]configuration.Parameters{"inmemory": map[string]any{}} if auth == "token" { - ln, err := net.Listen("tcp", "127.0.0.1:0") - suite.Nil(err, "no error finding free port for test auth server") + ln, err := lnCfg.Listen(suite.T().Context(), "tcp", "127.0.0.1:0") + suite.NoError(err, "no error finding free port for test auth server") defer ln.Close() //set test auth server host From e9eda8c5988d74172862b3b72cb1f8edf2226191 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 21:33:08 +0000 Subject: [PATCH 033/161] chore(deps): bump github/codeql-action/upload-sarif Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 03419cbda..e90e91bb3 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: sarif_file: results.sarif From d539556a8d03c48258d08207aaf918c202c90df6 Mon Sep 17 00:00:00 2001 From: kimsungmin1 <142377392+kimsungmin1@users.noreply.github.com> Date: Fri, 3 Jul 2026 21:28:56 +0900 Subject: [PATCH 034/161] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: kimsungmin1 <142377392+kimsungmin1@users.noreply.github.com> --- pkg/registry/registry_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 9388c8142..7d7b5a112 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -148,7 +148,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { if auth == "token" { ln, err := lnCfg.Listen(suite.T().Context(), "tcp", "127.0.0.1:0") - suite.NoError(err, "no error finding free port for test auth server") + suite.Require().NoError(err, "no error finding free port for test auth server") defer ln.Close() //set test auth server host From 143631f7356d7f2250540c044ae20277f495cc2f Mon Sep 17 00:00:00 2001 From: Mahesh Sadupalli Date: Fri, 3 Jul 2026 20:28:01 +0200 Subject: [PATCH 035/161] fix(engine): prevent Files.Lines panic on empty file Files.Lines guards against a nil entry but an empty file inside a chart is stored as a non-nil zero-length byte slice, so the trailing newline check indexes s[-1] and panics. The engine recovers the panic into a render error, making every template/install/upgrade/lint that references the file fail. Extend the guard to len(f[path]) == 0 and return an empty slice, matching the behaviour for missing files. Fixes #32279 Signed-off-by: Mahesh Sadupalli --- pkg/engine/files.go | 2 +- pkg/engine/files_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/pkg/engine/files.go b/pkg/engine/files.go index 7834cac2c..eeb04d76c 100644 --- a/pkg/engine/files.go +++ b/pkg/engine/files.go @@ -154,7 +154,7 @@ func (f files) AsSecrets() string { // {{ range .Files.Lines "foo/bar.html" }} // {{ . }}{{ end }} func (f files) Lines(path string) []string { - if f == nil || f[path] == nil { + if f == nil || len(f[path]) == 0 { return []string{} } s := string(f[path]) diff --git a/pkg/engine/files_test.go b/pkg/engine/files_test.go index f07f6afeb..b4318a597 100644 --- a/pkg/engine/files_test.go +++ b/pkg/engine/files_test.go @@ -30,6 +30,8 @@ var cases = []struct { {"story/author.txt", "Joseph Conrad"}, {"multiline/test.txt", "bar\nfoo\n"}, {"multiline/test_with_blank_lines.txt", "bar\nfoo\n\n\n"}, + {"empty/empty.txt", ""}, + {"empty/newline_only.txt", "\n"}, } func getTestFiles() files { @@ -109,3 +111,31 @@ func TestBlankLines(t *testing.T) { as.Equal("bar", out[0]) as.Empty(out[3]) } + +func TestLinesEmptyFile(t *testing.T) { + as := assert.New(t) + + f := getTestFiles() + + out := f.Lines("empty/empty.txt") + as.Empty(out) +} + +func TestLinesNewlineOnlyFile(t *testing.T) { + as := assert.New(t) + + f := getTestFiles() + + out := f.Lines("empty/newline_only.txt") + as.Len(out, 1) + as.Empty(out[0]) +} + +func TestLinesMissingFile(t *testing.T) { + as := assert.New(t) + + f := getTestFiles() + + out := f.Lines("nonexistent.txt") + as.Empty(out) +} From 07259ecc86521db556c4a18331241bbefc6bb6b2 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 08:06:02 +0200 Subject: [PATCH 036/161] chore: fix several checks issues from gocritic Signed-off-by: Matthieu MOREL --- .golangci.yml | 13 ----- internal/chart/v3/lint/rules/crds_test.go | 6 +-- internal/chart/v3/lint/rules/values_test.go | 2 +- internal/chart/v3/loader/directory.go | 2 +- internal/chart/v3/loader/load_test.go | 2 +- internal/chart/v3/util/chartfile.go | 2 +- internal/chart/v3/util/create.go | 6 +-- internal/chart/v3/util/expand.go | 4 +- internal/chart/v3/util/save.go | 6 +-- internal/chart/v3/util/save_test.go | 2 +- internal/fileutil/fileutil_test.go | 12 ++--- internal/plugin/installer/extractor.go | 8 ++-- internal/plugin/installer/http_installer.go | 6 +-- .../plugin/installer/http_installer_test.go | 48 +++++++++---------- internal/plugin/installer/installer.go | 2 +- internal/plugin/installer/local_installer.go | 6 +-- .../plugin/installer/local_installer_test.go | 10 ++-- internal/plugin/installer/oci_installer.go | 12 ++--- .../plugin/installer/oci_installer_test.go | 18 +++---- .../plugin/installer/plugin_structure_test.go | 20 ++++---- .../plugin/installer/vcs_installer_test.go | 2 +- .../plugin/installer/verification_test.go | 12 ++--- internal/plugin/sign_test.go | 4 +- internal/plugin/verify_test.go | 14 +++--- internal/sympath/walk_test.go | 2 +- internal/test/test.go | 2 +- internal/third_party/dep/fs/fs.go | 2 +- internal/third_party/dep/fs/fs_test.go | 38 +++++++-------- pkg/action/action.go | 4 +- pkg/action/dependency_test.go | 4 +- pkg/action/install.go | 8 ++-- pkg/action/package.go | 2 +- pkg/action/package_test.go | 2 +- pkg/action/pull.go | 2 +- pkg/chart/loader/load_test.go | 2 +- pkg/chart/v2/lint/rules/crds_test.go | 6 +-- pkg/chart/v2/lint/rules/values_test.go | 2 +- pkg/chart/v2/loader/directory.go | 2 +- pkg/chart/v2/loader/load_test.go | 2 +- pkg/chart/v2/util/chartfile.go | 2 +- pkg/chart/v2/util/create.go | 6 +-- pkg/chart/v2/util/expand.go | 4 +- pkg/chart/v2/util/save.go | 6 +-- pkg/chart/v2/util/save_test.go | 2 +- pkg/cli/values/options_test.go | 4 +- pkg/cmd/docs.go | 2 +- pkg/cmd/load_plugins.go | 5 +- pkg/cmd/plugin_package.go | 4 +- pkg/cmd/plugin_package_test.go | 12 ++--- pkg/cmd/plugin_uninstall_test.go | 10 ++-- pkg/cmd/plugin_verify_test.go | 10 ++-- pkg/cmd/pull_test.go | 6 +-- pkg/cmd/repo_add_test.go | 2 +- pkg/cmd/repo_remove.go | 2 +- pkg/cmd/template.go | 6 +-- pkg/downloader/cache.go | 4 +- pkg/downloader/cache_test.go | 2 +- pkg/downloader/chart_downloader.go | 6 +-- pkg/downloader/chart_downloader_test.go | 4 +- pkg/downloader/manager.go | 8 ++-- pkg/downloader/manager_test.go | 12 ++--- pkg/engine/engine.go | 2 +- pkg/getter/httpgetter_test.go | 2 +- pkg/pusher/ocipusher_test.go | 6 +-- pkg/registry/registry_test.go | 9 ++-- pkg/repo/v1/chartrepo.go | 8 ++-- pkg/repo/v1/index_test.go | 4 +- pkg/repo/v1/repo.go | 2 +- pkg/repo/v1/repo_test.go | 2 +- pkg/storage/driver/cfgmaps.go | 2 +- pkg/storage/driver/util.go | 2 +- pkg/strvals/literal_parser_test.go | 7 +-- pkg/strvals/parser.go | 4 +- pkg/strvals/parser_test.go | 17 +++---- 74 files changed, 236 insertions(+), 249 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b3ced6f1a..518e47052 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -94,32 +94,19 @@ linters: - emptyStringTest - exposedSyncMutex - filepathJoin - - httpNoBody - hugeParam - ifElseChain - importShadow - nestingReduce - nilValReturn - - octalLiteral - paramTypeCombine - - preferStringWriter - ptrToRefParam - rangeValCopy - - regexpSimplify - singleCaseSwitch - - sloppyReassign - - sloppyLen - - sprintfQuotedString - - stringConcatSimplify - - stringsCompare - - stringXbytes - todoCommentWithoutDetail - tooManyResultsChecker - - typeAssertChain - uncheckedInlineErr - unnamedResult - - unnecessaryDefer - - unslice - whyNoLint enable-all: true diff --git a/internal/chart/v3/lint/rules/crds_test.go b/internal/chart/v3/lint/rules/crds_test.go index b80339d7b..60cb1b5ba 100644 --- a/internal/chart/v3/lint/rules/crds_test.go +++ b/internal/chart/v3/lint/rules/crds_test.go @@ -45,11 +45,11 @@ func TestCrdWithEmptyDocument(t *testing.T) { `apiVersion: v1 name: test version: 0.1.0 -`), 0644) +`), 0o644) // CRD with comments before --- (creates empty document) crdsDir := filepath.Join(chartDir, "crds") - os.Mkdir(crdsDir, 0755) + os.Mkdir(crdsDir, 0o755) os.WriteFile(filepath.Join(crdsDir, "test.yaml"), []byte( `# Comments create empty document --- @@ -57,7 +57,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: test.example.io -`), 0644) +`), 0o644) linter := support.Linter{ChartDir: chartDir} Crds(&linter) diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index 54c7e6457..c0d2f5299 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -176,7 +176,7 @@ func TestValidateValuesFile(t *testing.T) { func createTestingSchema(t *testing.T, dir string) string { t.Helper() schemafile := filepath.Join(dir, "values.schema.json") - if err := os.WriteFile(schemafile, []byte(testSchema), 0700); err != nil { + if err := os.WriteFile(schemafile, []byte(testSchema), 0o700); err != nil { t.Fatalf("Failed to write schema to tmpdir: %s", err) } return schemafile diff --git a/internal/chart/v3/loader/directory.go b/internal/chart/v3/loader/directory.go index dfe3af3b2..7cf343568 100644 --- a/internal/chart/v3/loader/directory.go +++ b/internal/chart/v3/loader/directory.go @@ -114,7 +114,7 @@ func LoadDir(dir string) (*chart.Chart, error) { files = append(files, &archive.BufferedFile{Name: n, ModTime: fi.ModTime(), Data: data}) return nil } - if err = sympath.Walk(topdir, walk); err != nil { + if err := sympath.Walk(topdir, walk); err != nil { return c, err } diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index de9219a1b..a493104bf 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -377,7 +377,7 @@ func TestLoadInvalidArchive(t *testing.T) { h := &tar.Header{ Name: internalPath, - Mode: 0755, + Mode: 0o755, Size: int64(len(body)), ModTime: time.Now(), } diff --git a/internal/chart/v3/util/chartfile.go b/internal/chart/v3/util/chartfile.go index 25271e1cf..76dec9d47 100644 --- a/internal/chart/v3/util/chartfile.go +++ b/internal/chart/v3/util/chartfile.go @@ -58,7 +58,7 @@ func SaveChartfile(filename string, cf *chart.Metadata) error { if err != nil { return err } - return os.WriteFile(filename, out, 0644) + return os.WriteFile(filename, out, 0o644) } // IsChartDir validate a chart directory. diff --git a/internal/chart/v3/util/create.go b/internal/chart/v3/util/create.go index b3d75ac2d..dcb5bbb39 100644 --- a/internal/chart/v3/util/create.go +++ b/internal/chart/v3/util/create.go @@ -803,7 +803,7 @@ func Create(name, dir string) (string, error) { } } // Need to add the ChartsDir explicitly as it does not contain any file OOTB - if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0o755); err != nil { return cdir, err } return cdir, nil @@ -816,10 +816,10 @@ func transform(src, replacement string) []byte { } func writeFile(name string, content []byte) error { - if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(name), 0o755); err != nil { return err } - return os.WriteFile(name, content, 0644) + return os.WriteFile(name, content, 0o644) } func validateChartName(name string) error { diff --git a/internal/chart/v3/util/expand.go b/internal/chart/v3/util/expand.go index 5b057b8e0..df0652849 100644 --- a/internal/chart/v3/util/expand.go +++ b/internal/chart/v3/util/expand.go @@ -88,11 +88,11 @@ func Expand(dir string, r io.Reader) error { // Make sure the necessary subdirs get created. basedir := filepath.Dir(outpath) - if err := os.MkdirAll(basedir, 0755); err != nil { + if err := os.MkdirAll(basedir, 0o755); err != nil { return err } - if err := os.WriteFile(outpath, file.Data, 0644); err != nil { + if err := os.WriteFile(outpath, file.Data, 0o644); err != nil { return err } } diff --git a/internal/chart/v3/util/save.go b/internal/chart/v3/util/save.go index f886c6175..942e736ed 100644 --- a/internal/chart/v3/util/save.go +++ b/internal/chart/v3/util/save.go @@ -49,7 +49,7 @@ func SaveDir(c *chart.Chart, dest string) error { if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() { return fmt.Errorf("file %s already exists and is not a directory", outdir) } - if err := os.MkdirAll(outdir, 0755); err != nil { + if err := os.MkdirAll(outdir, 0o755); err != nil { return err } @@ -115,7 +115,7 @@ func Save(c *chart.Chart, outDir string) (string, error) { dir := filepath.Dir(filename) if stat, err := os.Stat(dir); err != nil { if errors.Is(err, fs.ErrNotExist) { - if err2 := os.MkdirAll(dir, 0755); err2 != nil { + if err2 := os.MkdirAll(dir, 0o755); err2 != nil { return "", err2 } } else { @@ -230,7 +230,7 @@ func writeToTar(out *tar.Writer, name string, body []byte, modTime time.Time) er // TODO: Do we need to create dummy parent directory names if none exist? h := &tar.Header{ Name: filepath.ToSlash(name), - Mode: 0644, + Mode: 0o644, Size: int64(len(body)), ModTime: modTime, } diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index 34e7d898e..cbe9b853f 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -258,7 +258,7 @@ func TestSaveDir(t *testing.T) { tmp2 := t.TempDir() c.Metadata.Name = "../ahab" pth := filepath.Join(tmp2, "tmpcharts") - if err := os.MkdirAll(filepath.Join(pth), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(pth), 0o755); err != nil { t.Fatal(err) } diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go index 07cbe7695..c78f70a3d 100644 --- a/internal/fileutil/fileutil_test.go +++ b/internal/fileutil/fileutil_test.go @@ -35,7 +35,7 @@ func TestAtomicWriteFile(t *testing.T) { testpath := filepath.Join(dir, "test") stringContent := "Test content" reader := bytes.NewReader([]byte(stringContent)) - mode := os.FileMode(0644) + mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) assert.NoError(t, err) @@ -56,7 +56,7 @@ func TestAtomicWriteFile_CreateTempError(t *testing.T) { invalidPath := "/invalid/path/that/does/not/exist/testfile" reader := bytes.NewReader([]byte("test content")) - mode := os.FileMode(0644) + mode := os.FileMode(0o644) err := AtomicWriteFile(invalidPath, reader, mode) assert.Error(t, err, "Expected error when CreateTemp fails") @@ -68,7 +68,7 @@ func TestAtomicWriteFile_EmptyContent(t *testing.T) { testpath := filepath.Join(dir, "empty_helm") reader := bytes.NewReader([]byte("")) - mode := os.FileMode(0644) + mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) assert.NoError(t, err, "AtomicWriteFile error with empty content") @@ -87,7 +87,7 @@ func TestAtomicWriteFile_LargeContent(t *testing.T) { // Create a large content string largeContent := strings.Repeat("HELM", 1024*1024) reader := bytes.NewReader([]byte(largeContent)) - mode := os.FileMode(0644) + mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) assert.NoError(t, err, "AtomicWriteFile error with large content") @@ -105,10 +105,10 @@ func TestPlatformAtomicWriteFile_OverwritesExisting(t *testing.T) { path := filepath.Join(dir, "overwrite_test") first := bytes.NewReader([]byte("first")) - require.NoError(t, PlatformAtomicWriteFile(path, first, 0644), "first write failed") + require.NoError(t, PlatformAtomicWriteFile(path, first, 0o644), "first write failed") second := bytes.NewReader([]byte("second")) - require.NoError(t, PlatformAtomicWriteFile(path, second, 0644), "second write failed") + require.NoError(t, PlatformAtomicWriteFile(path, second, 0o644), "second write failed") contents, err := os.ReadFile(path) require.NoError(t, err, "failed reading result") diff --git a/internal/plugin/installer/extractor.go b/internal/plugin/installer/extractor.go index 3af56ab56..85d695bd2 100644 --- a/internal/plugin/installer/extractor.go +++ b/internal/plugin/installer/extractor.go @@ -132,7 +132,7 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { return err } - if err := os.MkdirAll(targetDir, 0755); err != nil { + if err := os.MkdirAll(targetDir, 0o755); err != nil { return err } @@ -153,12 +153,12 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { switch header.Typeflag { case tar.TypeDir: - if err := os.MkdirAll(path, 0755); err != nil { + if err := os.MkdirAll(path, 0o755); err != nil { return err } case tar.TypeReg: // Ensure parent directory exists - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } outFile, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) @@ -189,6 +189,6 @@ func stripPluginName(name string) string { break } } - re := regexp.MustCompile(`(.*)-[0-9]+\..*`) + re := regexp.MustCompile(`(.*)-\d+\..*`) return re.ReplaceAllString(strippedName, `$1`) } diff --git a/internal/plugin/installer/http_installer.go b/internal/plugin/installer/http_installer.go index 5a2912d2e..92d3d686e 100644 --- a/internal/plugin/installer/http_installer.go +++ b/internal/plugin/installer/http_installer.go @@ -93,10 +93,10 @@ func (i *HTTPInstaller) Install() error { } filename := fmt.Sprintf("%s-%s.tgz", metadata.Name, metadata.Version) tarballPath := helmpath.DataPath("plugins", filename) - if err := os.MkdirAll(filepath.Dir(tarballPath), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(tarballPath), 0o755); err != nil { return fmt.Errorf("failed to create plugins directory: %w", err) } - if err := os.WriteFile(tarballPath, i.pluginData, 0644); err != nil { + if err := os.WriteFile(tarballPath, i.pluginData, 0o644); err != nil { return fmt.Errorf("failed to save tarball: %w", err) } @@ -112,7 +112,7 @@ func (i *HTTPInstaller) Install() error { // Save prov file if we have the data if i.provData != nil { provPath := tarballPath + ".prov" - if err := os.WriteFile(provPath, i.provData, 0644); err != nil { + if err := os.WriteFile(provPath, i.provData, 0o644); err != nil { slog.Debug("failed to save provenance file", "error", err) } } diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index efbca90c9..b080aa2ef 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -85,7 +85,7 @@ func TestHTTPInstaller(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { + if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) } @@ -132,7 +132,7 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { + if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) } @@ -164,7 +164,7 @@ func TestHTTPInstallerUpdate(t *testing.T) { source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { + if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) } @@ -219,8 +219,8 @@ func TestExtract(t *testing.T) { Name, Body string Mode int64 }{ - {"plugin.yaml", "plugin metadata", 0600}, - {"README.md", "some text", 0777}, + {"plugin.yaml", "plugin metadata", 0o600}, + {"README.md", "some text", 0o777}, } for _, file := range files { hdr := &tar.Header{ @@ -271,8 +271,8 @@ func TestExtract(t *testing.T) { } // Calculate expected permissions after umask is applied - expectedPluginYAMLPerm := os.FileMode(0600 &^ currentUmask) - expectedReadmePerm := os.FileMode(0777 &^ currentUmask) + expectedPluginYAMLPerm := os.FileMode(0o600 &^ currentUmask) + expectedReadmePerm := os.FileMode(0o777 &^ currentUmask) pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") if info, err := os.Stat(pluginYAMLFullPath); err != nil { @@ -361,13 +361,13 @@ func TestExtractWithNestedDirectories(t *testing.T) { Mode int64 TypeFlag byte }{ - {"plugin.yaml", "plugin metadata", 0600, tar.TypeReg}, - {"bin/", "", 0755, tar.TypeDir}, - {"bin/plugin", "#!/usr/bin/env sh\necho plugin", 0755, tar.TypeReg}, - {"docs/", "", 0755, tar.TypeDir}, - {"docs/README.md", "readme content", 0644, tar.TypeReg}, - {"docs/examples/", "", 0755, tar.TypeDir}, - {"docs/examples/example1.yaml", "example content", 0644, tar.TypeReg}, + {"plugin.yaml", "plugin metadata", 0o600, tar.TypeReg}, + {"bin/", "", 0o755, tar.TypeDir}, + {"bin/plugin", "#!/usr/bin/env sh\necho plugin", 0o755, tar.TypeReg}, + {"docs/", "", 0o755, tar.TypeDir}, + {"docs/README.md", "readme content", 0o644, tar.TypeReg}, + {"docs/examples/", "", 0o755, tar.TypeDir}, + {"docs/examples/example1.yaml", "example content", 0o644, tar.TypeReg}, } for _, file := range files { @@ -434,13 +434,13 @@ func TestExtractWithExistingDirectory(t *testing.T) { // Pre-create the cache directory structure cacheDir := filepath.Join(tempDir, "cache") - if err := os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0o755); err != nil { t.Fatal(err) } // Create a file in the existing directory existingFile := filepath.Join(cacheDir, "existing", "file.txt") - if err := os.WriteFile(existingFile, []byte("existing content"), 0644); err != nil { + if err := os.WriteFile(existingFile, []byte("existing content"), 0o644); err != nil { t.Fatal(err) } @@ -453,10 +453,10 @@ func TestExtractWithExistingDirectory(t *testing.T) { Mode int64 TypeFlag byte }{ - {"plugin.yaml", "plugin metadata", 0600, tar.TypeReg}, - {"existing/", "", 0755, tar.TypeDir}, - {"existing/dir/", "", 0755, tar.TypeDir}, - {"existing/dir/newfile.txt", "new content", 0644, tar.TypeReg}, + {"plugin.yaml", "plugin metadata", 0o600, tar.TypeReg}, + {"existing/", "", 0o755, tar.TypeDir}, + {"existing/dir/", "", 0o755, tar.TypeDir}, + {"existing/dir/newfile.txt", "new content", 0o644, tar.TypeReg}, } for _, file := range files { @@ -523,10 +523,10 @@ func TestExtractPluginInSubdirectory(t *testing.T) { Mode int64 TypeFlag byte }{ - {"my-plugin/", "", 0755, tar.TypeDir}, - {"my-plugin/plugin.yaml", "name: my-plugin\nversion: 1.0.0\nusage: test\ndescription: test plugin\ncommand: $HELM_PLUGIN_DIR/bin/my-plugin", 0644, tar.TypeReg}, - {"my-plugin/bin/", "", 0755, tar.TypeDir}, - {"my-plugin/bin/my-plugin", "#!/usr/bin/env sh\necho test", 0755, tar.TypeReg}, + {"my-plugin/", "", 0o755, tar.TypeDir}, + {"my-plugin/plugin.yaml", "name: my-plugin\nversion: 1.0.0\nusage: test\ndescription: test plugin\ncommand: $HELM_PLUGIN_DIR/bin/my-plugin", 0o644, tar.TypeReg}, + {"my-plugin/bin/", "", 0o755, tar.TypeDir}, + {"my-plugin/bin/my-plugin", "#!/usr/bin/env sh\necho test", 0o755, tar.TypeReg}, } for _, file := range files { diff --git a/internal/plugin/installer/installer.go b/internal/plugin/installer/installer.go index a7ca35ad4..865570773 100644 --- a/internal/plugin/installer/installer.go +++ b/internal/plugin/installer/installer.go @@ -73,7 +73,7 @@ type VerificationResult struct { // InstallWithOptions installs a plugin with options. func InstallWithOptions(i Installer, opts Options) (*VerificationResult, error) { - if err := os.MkdirAll(filepath.Dir(i.Path()), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(i.Path()), 0o755); err != nil { return nil, err } if _, pathErr := os.Stat(i.Path()); !os.IsNotExist(pathErr) { diff --git a/internal/plugin/installer/local_installer.go b/internal/plugin/installer/local_installer.go index 71407380f..8d067612f 100644 --- a/internal/plugin/installer/local_installer.go +++ b/internal/plugin/installer/local_installer.go @@ -117,10 +117,10 @@ func (i *LocalInstaller) installFromArchive() error { } filename := fmt.Sprintf("%s-%s.tgz", metadata.Name, metadata.Version) tarballPath := helmpath.DataPath("plugins", filename) - if err := os.MkdirAll(filepath.Dir(tarballPath), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(tarballPath), 0o755); err != nil { return fmt.Errorf("failed to create plugins directory: %w", err) } - if err := os.WriteFile(tarballPath, data, 0644); err != nil { + if err := os.WriteFile(tarballPath, data, 0o644); err != nil { return fmt.Errorf("failed to save tarball: %w", err) } @@ -128,7 +128,7 @@ func (i *LocalInstaller) installFromArchive() error { provSource := i.Source + ".prov" if provData, err := os.ReadFile(provSource); err == nil { provPath := tarballPath + ".prov" - if err := os.WriteFile(provPath, provData, 0644); err != nil { + if err := os.WriteFile(provPath, provData, 0o644); err != nil { slog.Debug("failed to save provenance file", "error", err) } } diff --git a/internal/plugin/installer/local_installer_test.go b/internal/plugin/installer/local_installer_test.go index 510c2880b..02d4d7bff 100644 --- a/internal/plugin/installer/local_installer_test.go +++ b/internal/plugin/installer/local_installer_test.go @@ -34,7 +34,7 @@ func TestLocalInstaller(t *testing.T) { ensure.HelmHome(t) // Make a temp dir tdir := t.TempDir() - if err := os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0644); err != nil { + if err := os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0o644); err != nil { t.Fatal(err) } @@ -51,7 +51,7 @@ func TestLocalInstaller(t *testing.T) { if i.Path() != helmpath.DataPath("plugins", "echo-v1") { t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) } - defer os.RemoveAll(filepath.Dir(helmpath.DataPath())) // helmpath.DataPath is like /tmp/helm013130971/helm + os.RemoveAll(filepath.Dir(helmpath.DataPath())) // helmpath.DataPath is like /tmp/helm013130971/helm } func TestLocalInstallerNotAFolder(t *testing.T) { @@ -87,8 +87,8 @@ func TestLocalInstallerTarball(t *testing.T) { Body string Mode int64 }{ - {"test-plugin/plugin.yaml", "name: test-plugin\napiVersion: v1\ntype: cli/v1\nruntime: subprocess\nversion: 1.0.0\nconfig:\n shortHelp: test\n longHelp: test\nruntimeConfig:\n platformCommand:\n - command: echo", 0644}, - {"test-plugin/bin/test-plugin", "#!/usr/bin/env sh\necho test", 0755}, + {"test-plugin/plugin.yaml", "name: test-plugin\napiVersion: v1\ntype: cli/v1\nruntime: subprocess\nversion: 1.0.0\nconfig:\n shortHelp: test\n longHelp: test\nruntimeConfig:\n platformCommand:\n - command: echo", 0o644}, + {"test-plugin/bin/test-plugin", "#!/usr/bin/env sh\necho test", 0o755}, } for _, file := range files { @@ -113,7 +113,7 @@ func TestLocalInstallerTarball(t *testing.T) { } // Write tarball to file - if err := os.WriteFile(tarballPath, buf.Bytes(), 0644); err != nil { + if err := os.WriteFile(tarballPath, buf.Bytes(), 0o644); err != nil { t.Fatal(err) } diff --git a/internal/plugin/installer/oci_installer.go b/internal/plugin/installer/oci_installer.go index 50d01522a..383ddb914 100644 --- a/internal/plugin/installer/oci_installer.go +++ b/internal/plugin/installer/oci_installer.go @@ -104,10 +104,10 @@ func (i *OCIInstaller) Install() error { filename := fmt.Sprintf("%s-%s.tgz", metadata.Name, metadata.Version) tarballPath := helmpath.DataPath("plugins", filename) - if err := os.MkdirAll(filepath.Dir(tarballPath), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(tarballPath), 0o755); err != nil { return fmt.Errorf("failed to create plugins directory: %w", err) } - if err := os.WriteFile(tarballPath, i.pluginData, 0644); err != nil { + if err := os.WriteFile(tarballPath, i.pluginData, 0o644); err != nil { return fmt.Errorf("failed to save tarball: %w", err) } @@ -123,7 +123,7 @@ func (i *OCIInstaller) Install() error { // Save prov file if we have the data if i.provData != nil { provPath := tarballPath + ".prov" - if err := os.WriteFile(provPath, i.provData, 0644); err != nil { + if err := os.WriteFile(provPath, i.provData, 0o644); err != nil { slog.Debug("failed to save provenance file", "error", err) } } @@ -134,7 +134,7 @@ func (i *OCIInstaller) Install() error { } // Create cache directory - if err := os.MkdirAll(i.CacheDir, 0755); err != nil { + if err := os.MkdirAll(i.CacheDir, 0o755); err != nil { return fmt.Errorf("failed to create cache directory: %w", err) } @@ -229,12 +229,12 @@ func extractTar(r io.Reader, targetDir string) error { switch header.Typeflag { case tar.TypeDir: - if err := os.MkdirAll(path, 0755); err != nil { + if err := os.MkdirAll(path, 0o755); err != nil { return err } case tar.TypeReg: dir := filepath.Dir(path) - if err := os.MkdirAll(dir, 0755); err != nil { + if err := os.MkdirAll(dir, 0o755); err != nil { return err } diff --git a/internal/plugin/installer/oci_installer_test.go b/internal/plugin/installer/oci_installer_test.go index 1f25f4e76..650e46add 100644 --- a/internal/plugin/installer/oci_installer_test.go +++ b/internal/plugin/installer/oci_installer_test.go @@ -58,7 +58,7 @@ command: "$HELM_PLUGIN_DIR/bin/%s" `, pluginName, pluginName) header := &tar.Header{ Name: "plugin.yaml", - Mode: 0644, + Mode: 0o644, Size: int64(len(pluginYAML)), Typeflag: tar.TypeReg, } @@ -72,7 +72,7 @@ command: "$HELM_PLUGIN_DIR/bin/%s" // Add bin directory dirHeader := &tar.Header{ Name: "bin/", - Mode: 0755, + Mode: 0o755, Typeflag: tar.TypeDir, } if err := tarWriter.WriteHeader(dirHeader); err != nil { @@ -83,7 +83,7 @@ command: "$HELM_PLUGIN_DIR/bin/%s" execContent := fmt.Sprintf("#!/bin/sh\necho '%s test plugin'", pluginName) execHeader := &tar.Header{ Name: "bin/" + pluginName, - Mode: 0755, + Mode: 0o755, Size: int64(len(execContent)), Typeflag: tar.TypeReg, } @@ -539,7 +539,7 @@ func TestOCIInstaller_Install_ComponentExtraction(t *testing.T) { execPath := filepath.Join(tempDir, "bin", pluginName) if info, err := os.Stat(execPath); err != nil { t.Errorf("executable not found: %v", err) - } else if info.Mode()&0111 == 0 { + } else if info.Mode()&0o111 == 0 { t.Error("file is not executable") } @@ -561,7 +561,7 @@ func TestExtractTarGz(t *testing.T) { testContent := "test content" header := &tar.Header{ Name: "test-file.txt", - Mode: 0644, + Mode: 0o644, Size: int64(len(testContent)), Typeflag: tar.TypeReg, } @@ -577,7 +577,7 @@ func TestExtractTarGz(t *testing.T) { // Add a test directory dirHeader := &tar.Header{ Name: "test-dir/", - Mode: 0755, + Mode: 0o755, Typeflag: tar.TypeDir, } @@ -634,7 +634,7 @@ func TestExtractTar_UnknownFileType(t *testing.T) { testContent := "test content" header := &tar.Header{ Name: "test-file.txt", - Mode: 0644, + Mode: 0o644, Size: int64(len(testContent)), Typeflag: tar.TypeReg, } @@ -650,7 +650,7 @@ func TestExtractTar_UnknownFileType(t *testing.T) { // Test unknown file type unknownHeader := &tar.Header{ Name: "unknown-type", - Mode: 0644, + Mode: 0o644, Typeflag: tar.TypeSymlink, // Use a type that's not handled } @@ -686,7 +686,7 @@ func TestExtractTar_SuccessfulExtraction(t *testing.T) { testContent := "test content" header := &tar.Header{ Name: "test-file.txt", - Mode: 0644, + Mode: 0o644, Size: int64(len(testContent)), Typeflag: tar.TypeReg, } diff --git a/internal/plugin/installer/plugin_structure_test.go b/internal/plugin/installer/plugin_structure_test.go index c8766ce59..182eb9bd8 100644 --- a/internal/plugin/installer/plugin_structure_test.go +++ b/internal/plugin/installer/plugin_structure_test.go @@ -31,7 +31,7 @@ func TestDetectPluginRoot(t *testing.T) { { name: "plugin.yaml at root", setup: func(dir string) error { - return os.WriteFile(filepath.Join(dir, "plugin.yaml"), []byte("name: test"), 0644) + return os.WriteFile(filepath.Join(dir, "plugin.yaml"), []byte("name: test"), 0o644) }, expectRoot: ".", expectError: false, @@ -40,10 +40,10 @@ func TestDetectPluginRoot(t *testing.T) { name: "plugin.yaml in subdirectory", setup: func(dir string) error { subdir := filepath.Join(dir, "my-plugin") - if err := os.MkdirAll(subdir, 0755); err != nil { + if err := os.MkdirAll(subdir, 0o755); err != nil { return err } - return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte("name: test"), 0644) + return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte("name: test"), 0o644) }, expectRoot: "my-plugin", expectError: false, @@ -51,7 +51,7 @@ func TestDetectPluginRoot(t *testing.T) { { name: "no plugin.yaml", setup: func(dir string) error { - return os.WriteFile(filepath.Join(dir, "README.md"), []byte("test"), 0644) + return os.WriteFile(filepath.Join(dir, "README.md"), []byte("test"), 0o644) }, expectRoot: "", expectError: true, @@ -60,10 +60,10 @@ func TestDetectPluginRoot(t *testing.T) { name: "plugin.yaml in nested subdirectory (should not find)", setup: func(dir string) error { subdir := filepath.Join(dir, "outer", "inner") - if err := os.MkdirAll(subdir, 0755); err != nil { + if err := os.MkdirAll(subdir, 0o755); err != nil { return err } - return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte("name: test"), 0644) + return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte("name: test"), 0o644) }, expectRoot: "", expectError: true, @@ -110,14 +110,14 @@ func TestValidatePluginName(t *testing.T) { name: "matching directory and plugin name", setup: func(dir string) error { subdir := filepath.Join(dir, "my-plugin") - if err := os.MkdirAll(subdir, 0755); err != nil { + if err := os.MkdirAll(subdir, 0o755); err != nil { return err } yaml := `name: my-plugin version: 1.0.0 usage: test description: test` - return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte(yaml), 0644) + return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte(yaml), 0o644) }, pluginRoot: "my-plugin", expectedName: "my-plugin", @@ -127,14 +127,14 @@ description: test` name: "different directory and plugin name", setup: func(dir string) error { subdir := filepath.Join(dir, "wrong-name") - if err := os.MkdirAll(subdir, 0755); err != nil { + if err := os.MkdirAll(subdir, 0o755); err != nil { return err } yaml := `name: my-plugin version: 1.0.0 usage: test description: test` - return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte(yaml), 0644) + return os.WriteFile(filepath.Join(subdir, "plugin.yaml"), []byte(yaml), 0o644) }, pluginRoot: "wrong-name", expectedName: "wrong-name", diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 54f94c724..401f2b921 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -52,7 +52,7 @@ func (r *testRepo) UpdateVersion(version string) error { func TestVCSInstaller(t *testing.T) { ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { + if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) } diff --git a/internal/plugin/installer/verification_test.go b/internal/plugin/installer/verification_test.go index e05cda7fd..d3824a0fc 100644 --- a/internal/plugin/installer/verification_test.go +++ b/internal/plugin/installer/verification_test.go @@ -291,7 +291,7 @@ func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { // Create a .prov file but make it inaccessible (simulate permission error) provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("test"), 0000); err != nil { + if err := os.WriteFile(provFile, []byte("test"), 0o000); err != nil { t.Fatalf("Failed to create inaccessible provenance file: %v", err) } defer os.Remove(provFile) @@ -333,7 +333,7 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatalf("Failed to create plugin directory: %v", err) } @@ -346,7 +346,7 @@ version: 1.0.0 runtimeConfig: platformCommand: - command: echo` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0o644); err != nil { t.Fatalf("Failed to create plugin.yaml: %v", err) } @@ -404,7 +404,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { t.Fatalf("Failed to create provenance file: %v", err) } } @@ -414,7 +414,7 @@ func createProvFileInvalidFormat(t *testing.T, provFile string) { // Create an invalid provenance file (not PGP signed format) invalidProv := "This is not a valid PGP signed message" - if err := os.WriteFile(provFile, []byte(invalidProv), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(invalidProv), 0o644); err != nil { t.Fatalf("Failed to create invalid provenance file: %v", err) } } @@ -427,7 +427,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0644); err != nil { + if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { t.Fatalf("Failed to create test keyring: %v", err) } diff --git a/internal/plugin/sign_test.go b/internal/plugin/sign_test.go index fce2dbeb3..7e97a82aa 100644 --- a/internal/plugin/sign_test.go +++ b/internal/plugin/sign_test.go @@ -28,7 +28,7 @@ func TestSignPlugin(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ version: 1.0.0 runtimeConfig: platformCommand: - command: echo` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644); err != nil { t.Fatal(err) } diff --git a/internal/plugin/verify_test.go b/internal/plugin/verify_test.go index 9c907788f..2828d30b6 100644 --- a/internal/plugin/verify_test.go +++ b/internal/plugin/verify_test.go @@ -41,11 +41,11 @@ func TestVerifyPlugin(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(tempDir, "verify-test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatal(err) } @@ -86,7 +86,7 @@ func TestVerifyPlugin(t *testing.T) { // Write the signature to .prov file provFile := tarballPath + ".prov" - if err := os.WriteFile(provFile, []byte(sig), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(sig), 0o644); err != nil { t.Fatal(err) } @@ -126,11 +126,11 @@ func TestVerifyPluginBadSignature(t *testing.T) { // Create a plugin tarball pluginDir := filepath.Join(tempDir, "bad-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatal(err) } @@ -158,7 +158,7 @@ InvalidSignatureData -----END PGP SIGNATURE-----` provFile := tarballPath + ".prov" - if err := os.WriteFile(provFile, []byte(badSig), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(badSig), 0o644); err != nil { t.Fatal(err) } @@ -185,7 +185,7 @@ func TestVerifyPluginMissingProvenance(t *testing.T) { tarballPath := filepath.Join(tempDir, "no-prov.tar.gz") // Create a minimal tarball - if err := os.WriteFile(tarballPath, []byte("dummy"), 0644); err != nil { + if err := os.WriteFile(tarballPath, []byte("dummy"), 0o644); err != nil { t.Fatal(err) } diff --git a/internal/sympath/walk_test.go b/internal/sympath/walk_test.go index b5bffbdab..76ed39cac 100644 --- a/internal/sympath/walk_test.go +++ b/internal/sympath/walk_test.go @@ -90,7 +90,7 @@ func makeTree(t *testing.T) { fd.Close() } } else { - require.NoError(t, os.Mkdir(path, 0770), "makeTree") + require.NoError(t, os.Mkdir(path, 0o770), "makeTree") } }) } diff --git a/internal/test/test.go b/internal/test/test.go index 202e015ab..ba4ea41e7 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -87,7 +87,7 @@ func update(filename string, in []byte) error { if !*updateGolden { return nil } - return os.WriteFile(filename, normalize(in), 0666) + return os.WriteFile(filename, normalize(in), 0o666) } func normalize(in []byte) []byte { diff --git a/internal/third_party/dep/fs/fs.go b/internal/third_party/dep/fs/fs.go index 3140cf91e..2607c73ac 100644 --- a/internal/third_party/dep/fs/fs.go +++ b/internal/third_party/dep/fs/fs.go @@ -193,7 +193,7 @@ func CopyFile(src, dst string) (err error) { } // Check for write errors on Close - if err = out.Close(); err != nil { + if err := out.Close(); err != nil { return err } diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index 806e33c28..6eed3f055 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -59,12 +59,12 @@ func TestRenameWithFallback(t *testing.T) { } srcpath = filepath.Join(dir, "a") - if err := os.MkdirAll(srcpath, 0777); err != nil { + if err := os.MkdirAll(srcpath, 0o777); err != nil { t.Fatal(err) } dstpath := filepath.Join(dir, "b") - if err := os.MkdirAll(dstpath, 0777); err != nil { + if err := os.MkdirAll(dstpath, 0o777); err != nil { t.Fatal(err) } @@ -77,7 +77,7 @@ func TestCopyDir(t *testing.T) { dir := t.TempDir() srcdir := filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0755); err != nil { + if err := os.MkdirAll(srcdir, 0o755); err != nil { t.Fatal(err) } @@ -94,7 +94,7 @@ func TestCopyDir(t *testing.T) { for i, file := range files { fn := filepath.Join(srcdir, file.path) dn := filepath.Dir(fn) - if err := os.MkdirAll(dn, 0755); err != nil { + if err := os.MkdirAll(dn, 0o755); err != nil { t.Fatal(err) } @@ -103,7 +103,7 @@ func TestCopyDir(t *testing.T) { t.Fatal(err) } - if _, err = fh.Write([]byte(file.contents)); err != nil { + if _, err = fh.WriteString(file.contents); err != nil { t.Fatal(err) } fh.Close() @@ -171,7 +171,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) { cleanup := setupInaccessibleDir(t, func(dir string) error { srcdir = filepath.Join(dir, "src") - return os.MkdirAll(srcdir, 0755) + return os.MkdirAll(srcdir, 0o755) }) defer cleanup() @@ -203,7 +203,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0755); err != nil { + if err := os.MkdirAll(srcdir, 0o755); err != nil { t.Fatal(err) } @@ -247,12 +247,12 @@ func TestCopyDirFail_DstExists(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err = os.MkdirAll(srcdir, 0755); err != nil { + if err = os.MkdirAll(srcdir, 0o755); err != nil { t.Fatal(err) } dstdir = filepath.Join(dir, "dst") - if err = os.MkdirAll(dstdir, 0755); err != nil { + if err = os.MkdirAll(dstdir, 0o755); err != nil { t.Fatal(err) } @@ -288,7 +288,7 @@ func TestCopyDirFailOpen(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0755); err != nil { + if err := os.MkdirAll(srcdir, 0o755); err != nil { t.Fatal(err) } @@ -300,7 +300,7 @@ func TestCopyDirFailOpen(t *testing.T) { srcf.Close() // setup source file so that it cannot be read - if err = os.Chmod(srcfn, 0222); err != nil { + if err = os.Chmod(srcfn, 0o222); err != nil { t.Fatal(err) } @@ -320,7 +320,7 @@ func TestCopyFile(t *testing.T) { } want := "hello world" - if _, err := srcf.Write([]byte(want)); err != nil { + if _, err := srcf.WriteString(want); err != nil { t.Fatal(err) } srcf.Close() @@ -433,7 +433,7 @@ func TestCopyFileFail(t *testing.T) { cleanup := setupInaccessibleDir(t, func(dir string) error { dstdir = filepath.Join(dir, "dir") - return os.Mkdir(dstdir, 0777) + return os.Mkdir(dstdir, 0o777) }) defer cleanup() @@ -463,12 +463,12 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() { subdir := filepath.Join(dir, "dir") cleanup := func() { - if err := os.Chmod(subdir, 0777); err != nil { + if err := os.Chmod(subdir, 0o777); err != nil { t.Error(err) } } - if err := os.Mkdir(subdir, 0777); err != nil { + if err := os.Mkdir(subdir, 0o777); err != nil { cleanup() t.Fatal(err) return nil @@ -480,7 +480,7 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() { return nil } - if err := os.Chmod(subdir, 0666); err != nil { + if err := os.Chmod(subdir, 0o666); err != nil { cleanup() t.Fatal(err) return nil @@ -506,7 +506,7 @@ func TestIsDir(t *testing.T) { cleanup := setupInaccessibleDir(t, func(dir string) error { dn = filepath.Join(dir, "dir") - return os.Mkdir(dn, 0777) + return os.Mkdir(dn, 0o777) }) defer cleanup() @@ -552,7 +552,7 @@ func TestIsSymlink(t *testing.T) { dir := t.TempDir() dirPath := filepath.Join(dir, "directory") - if err := os.MkdirAll(dirPath, 0777); err != nil { + if err := os.MkdirAll(dirPath, 0o777); err != nil { t.Fatal(err) } @@ -582,7 +582,7 @@ func TestIsSymlink(t *testing.T) { inaccessibleFile = filepath.Join(dir, "file") if fh, err := os.Create(inaccessibleFile); err != nil { return err - } else if err = fh.Close(); err != nil { + } else if err := fh.Close(); err != nil { return err } diff --git a/pkg/action/action.go b/pkg/action/action.go index 6e5d8c15a..8105083f9 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -484,9 +484,9 @@ func (cfg *Configuration) renderResources(ctx context.Context, ch *chart.Chart, if includeCrds { for _, crd := range ch.CRDObjects() { if outputDir == "" { - fmt.Fprintf(b, "---\n# Source: %s\n%s\n", crd.Filename, string(crd.File.Data[:])) + fmt.Fprintf(b, "---\n# Source: %s\n%s\n", crd.Filename, string(crd.File.Data)) } else { - err = writeToFile(outputDir, crd.Filename, string(crd.File.Data[:]), fileWritten[crd.Filename]) + err = writeToFile(outputDir, crd.Filename, string(crd.File.Data), fileWritten[crd.Filename]) if err != nil { return hs, b, "", err } diff --git a/pkg/action/dependency_test.go b/pkg/action/dependency_test.go index 5be7bf5a9..3899c20fc 100644 --- a/pkg/action/dependency_test.go +++ b/pkg/action/dependency_test.go @@ -70,7 +70,7 @@ func TestDependencyStatus_Dashes(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0700); err != nil { + if err := os.MkdirAll(chartpath, 0o700); err != nil { t.Fatal(err) } @@ -104,7 +104,7 @@ func TestStatArchiveForStatus(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0700); err != nil { + if err := os.MkdirAll(chartpath, 0o700); err != nil { t.Fatal(err) } diff --git a/pkg/action/install.go b/pkg/action/install.go index fcfae7214..d36d2fc3e 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -68,7 +68,7 @@ import ( // since there can be filepath in front of it. const notesFileSuffix = "NOTES.txt" -const defaultDirectoryPermission = 0755 +const defaultDirectoryPermission = 0o755 // Install performs an installation operation. type Install struct { @@ -718,7 +718,7 @@ func (i *Install) replaceRelease(rel *release.Release) error { // write the to /. controls if the file is created or content will be appended func writeToFile(outputDir string, name string, data string, appendData bool) error { - outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) + outfileName := outputDir + string(filepath.Separator) + name err := ensureDirectoryForFile(outfileName) if err != nil { @@ -744,7 +744,7 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er func createOrOpenFile(filename string, appendData bool) (*os.File, error) { if appendData { - return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600) + return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0o600) } return os.Create(filename) } @@ -976,7 +976,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( dl.Options = append(dl.Options, getter.WithBasicAuth(c.Username, c.Password)) } - if err := os.MkdirAll(settings.RepositoryCache, 0755); err != nil { + if err := os.MkdirAll(settings.RepositoryCache, 0o755); err != nil { return "", err } diff --git a/pkg/action/package.go b/pkg/action/package.go index 86426b412..002203f40 100644 --- a/pkg/action/package.go +++ b/pkg/action/package.go @@ -194,7 +194,7 @@ func (p *Package) Clearsign(filename string) error { return err } - return os.WriteFile(filename+".prov", []byte(sig), 0644) + return os.WriteFile(filename+".prov", []byte(sig), 0o644) } // promptUser implements provenance.PassphraseFetcher diff --git a/pkg/action/package_test.go b/pkg/action/package_test.go index f8a55c0e0..ccba4f847 100644 --- a/pkg/action/package_test.go +++ b/pkg/action/package_test.go @@ -92,7 +92,7 @@ func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { passphrase := "secret-from-stdin" go func() { - _, err = w.Write([]byte(passphrase + "\n")) + _, err = w.WriteString(passphrase + "\n") require.NoError(t, err) }() diff --git a/pkg/action/pull.go b/pkg/action/pull.go index dd051167b..168011d40 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -162,7 +162,7 @@ func (p *Pull) Run(chartRef string) (string, error) { } if _, err := os.Stat(udCheck); err != nil { - if err := os.MkdirAll(udCheck, 0755); err != nil { + if err := os.MkdirAll(udCheck, 0o755); err != nil { return out.String(), fmt.Errorf("failed to untar (mkdir): %w", err) } } else { diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 40f46c09b..a42861eac 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -55,7 +55,7 @@ description: A test chart for name, data := range files { header := &tar.Header{ Name: filepath.Join(chartName, name), - Mode: 0644, + Mode: 0o644, Size: int64(len(data)), ModTime: time.Now(), } diff --git a/pkg/chart/v2/lint/rules/crds_test.go b/pkg/chart/v2/lint/rules/crds_test.go index 759bb54fa..7016c4d9a 100644 --- a/pkg/chart/v2/lint/rules/crds_test.go +++ b/pkg/chart/v2/lint/rules/crds_test.go @@ -45,11 +45,11 @@ func TestCrdWithEmptyDocument(t *testing.T) { `apiVersion: v1 name: test version: 0.1.0 -`), 0644) +`), 0o644) // CRD with comments before --- (creates empty document) crdsDir := filepath.Join(chartDir, "crds") - os.Mkdir(crdsDir, 0755) + os.Mkdir(crdsDir, 0o755) os.WriteFile(filepath.Join(crdsDir, "test.yaml"), []byte( `# Comments create empty document --- @@ -57,7 +57,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: test.example.io -`), 0644) +`), 0o644) linter := support.Linter{ChartDir: chartDir} Crds(&linter) diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index 54c7e6457..c0d2f5299 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -176,7 +176,7 @@ func TestValidateValuesFile(t *testing.T) { func createTestingSchema(t *testing.T, dir string) string { t.Helper() schemafile := filepath.Join(dir, "values.schema.json") - if err := os.WriteFile(schemafile, []byte(testSchema), 0700); err != nil { + if err := os.WriteFile(schemafile, []byte(testSchema), 0o700); err != nil { t.Fatalf("Failed to write schema to tmpdir: %s", err) } return schemafile diff --git a/pkg/chart/v2/loader/directory.go b/pkg/chart/v2/loader/directory.go index 82578d924..a609ecbbf 100644 --- a/pkg/chart/v2/loader/directory.go +++ b/pkg/chart/v2/loader/directory.go @@ -114,7 +114,7 @@ func LoadDir(dir string) (*chart.Chart, error) { files = append(files, &archive.BufferedFile{Name: n, ModTime: fi.ModTime(), Data: data}) return nil } - if err = sympath.Walk(topdir, walk); err != nil { + if err := sympath.Walk(topdir, walk); err != nil { return c, err } diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index be7041386..e422c30de 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -430,7 +430,7 @@ func TestLoadInvalidArchive(t *testing.T) { h := &tar.Header{ Name: internalPath, - Mode: 0755, + Mode: 0o755, Size: int64(len(body)), ModTime: time.Now(), } diff --git a/pkg/chart/v2/util/chartfile.go b/pkg/chart/v2/util/chartfile.go index 1f9c712b2..525f1efd4 100644 --- a/pkg/chart/v2/util/chartfile.go +++ b/pkg/chart/v2/util/chartfile.go @@ -67,7 +67,7 @@ func SaveChartfile(filename string, cf *chart.Metadata) error { if err != nil { return err } - return os.WriteFile(filename, out, 0644) + return os.WriteFile(filename, out, 0o644) } // IsChartDir validate a chart directory. diff --git a/pkg/chart/v2/util/create.go b/pkg/chart/v2/util/create.go index 36e3bfe72..82e32d90d 100644 --- a/pkg/chart/v2/util/create.go +++ b/pkg/chart/v2/util/create.go @@ -802,7 +802,7 @@ func Create(name, dir string) (string, error) { } } // Need to add the ChartsDir explicitly as it does not contain any file OOTB - if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0o755); err != nil { return cdir, err } return cdir, nil @@ -815,10 +815,10 @@ func transform(src, replacement string) []byte { } func writeFile(name string, content []byte) error { - if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(name), 0o755); err != nil { return err } - return os.WriteFile(name, content, 0644) + return os.WriteFile(name, content, 0o644) } func validateChartName(name string) error { diff --git a/pkg/chart/v2/util/expand.go b/pkg/chart/v2/util/expand.go index 6022d5869..e33cff2d7 100644 --- a/pkg/chart/v2/util/expand.go +++ b/pkg/chart/v2/util/expand.go @@ -88,11 +88,11 @@ func Expand(dir string, r io.Reader) error { // Make sure the necessary subdirs get created. basedir := filepath.Dir(outpath) - if err := os.MkdirAll(basedir, 0755); err != nil { + if err := os.MkdirAll(basedir, 0o755); err != nil { return err } - if err := os.WriteFile(outpath, file.Data, 0644); err != nil { + if err := os.WriteFile(outpath, file.Data, 0o644); err != nil { return err } } diff --git a/pkg/chart/v2/util/save.go b/pkg/chart/v2/util/save.go index e66d86991..d8189c8bf 100644 --- a/pkg/chart/v2/util/save.go +++ b/pkg/chart/v2/util/save.go @@ -49,7 +49,7 @@ func SaveDir(c *chart.Chart, dest string) error { if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() { return fmt.Errorf("file %s already exists and is not a directory", outdir) } - if err := os.MkdirAll(outdir, 0755); err != nil { + if err := os.MkdirAll(outdir, 0o755); err != nil { return err } @@ -115,7 +115,7 @@ func Save(c *chart.Chart, outDir string) (string, error) { dir := filepath.Dir(filename) if stat, err := os.Stat(dir); err != nil { if errors.Is(err, fs.ErrNotExist) { - if err2 := os.MkdirAll(dir, 0755); err2 != nil { + if err2 := os.MkdirAll(dir, 0o755); err2 != nil { return "", err2 } } else { @@ -242,7 +242,7 @@ func writeToTar(out *tar.Writer, name string, body []byte, modTime time.Time) er // TODO: Do we need to create dummy parent directory names if none exist? h := &tar.Header{ Name: filepath.ToSlash(name), - Mode: 0644, + Mode: 0o644, Size: int64(len(body)), ModTime: modTime, } diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index 2f2b73efd..4870378d6 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -262,7 +262,7 @@ func TestSaveDir(t *testing.T) { tmp2 := t.TempDir() c.Metadata.Name = "../ahab" pth := filepath.Join(tmp2, "tmpcharts") - if err := os.MkdirAll(filepath.Join(pth), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(pth), 0o755); err != nil { t.Fatal(err) } diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index f6a116f18..498f2d3ba 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -91,7 +91,7 @@ func TestReadFile(t *testing.T) { tmpDir := t.TempDir() filePath := filepath.Join(tmpDir, "test.txt") content := []byte("local file content") - require.NoError(t, os.WriteFile(filePath, content, 0644)) + require.NoError(t, os.WriteFile(filePath, content, 0o644)) return filePath, func() {} // cleanup handled by t.TempDir() }, expectError: false, @@ -152,7 +152,7 @@ func TestReadFile(t *testing.T) { fileName := "ftp_file.txt" // Valid filename for filesystem filePath := filepath.Join(tmpDir, fileName) content := []byte("local fallback content") - require.NoError(t, os.WriteFile(filePath, content, 0644)) + require.NoError(t, os.WriteFile(filePath, content, 0o644)) return filePath, func() {} }, expectError: false, diff --git a/pkg/cmd/docs.go b/pkg/cmd/docs.go index 7fae60743..6463170b9 100644 --- a/pkg/cmd/docs.go +++ b/pkg/cmd/docs.go @@ -86,7 +86,7 @@ func (o *docsOptions) run(_ io.Writer) error { base := filepath.Base(filename) name := strings.TrimSuffix(base, path.Ext(base)) title := cases.Title(language.Und, cases.NoLower).String(strings.ReplaceAll(name, "_", " ")) - return fmt.Sprintf("---\ntitle: \"%s\"\n---\n\n", title) + return fmt.Sprintf("---\ntitle: %q\n---\n\n", title) } return doc.GenMarkdownTreeCustom(o.topCmd, o.dest, hdrFunc, standardLinks) diff --git a/pkg/cmd/load_plugins.go b/pkg/cmd/load_plugins.go index b6cc38ce6..474eaea2e 100644 --- a/pkg/cmd/load_plugins.go +++ b/pkg/cmd/load_plugins.go @@ -220,8 +220,7 @@ type pluginCommand struct { // and add the dynamic completion hook to call the optional plugin.complete func loadCompletionForPlugin(pluginCmd *cobra.Command, plug plugin.Plugin) { // Parse the yaml file providing the plugin's sub-commands and flags - cmds, err := loadFile(strings.Join( - []string{plug.Dir(), pluginStaticCompletionFile}, string(filepath.Separator))) + cmds, err := loadFile(plug.Dir() + string(filepath.Separator) + pluginStaticCompletionFile) if err != nil { // The file could be missing or invalid. No static completion for this plugin. @@ -351,7 +350,7 @@ func pluginDynamicComp(plug plugin.Plugin, cmd *cobra.Command, args []string, to } // We will call the dynamic completion script of the plugin - main := strings.Join([]string{plug.Dir(), pluginDynamicCompletionExecutable}, string(filepath.Separator)) + main := plug.Dir() + string(filepath.Separator) + pluginDynamicCompletionExecutable // We must include all sub-commands passed on the command-line. // To do that, we pass-in the entire CommandPath, except the first two elements diff --git a/pkg/cmd/plugin_package.go b/pkg/cmd/plugin_package.go index d82f4d2cc..019ae6d4a 100644 --- a/pkg/cmd/plugin_package.go +++ b/pkg/cmd/plugin_package.go @@ -91,7 +91,7 @@ func (o *pluginPackageOptions) run(out io.Writer) error { } // Create destination directory if needed - if err := os.MkdirAll(o.destination, 0755); err != nil { + if err := os.MkdirAll(o.destination, 0o755); err != nil { return err } @@ -158,7 +158,7 @@ func (o *pluginPackageOptions) run(out io.Writer) error { // Write the signature provFile := tarballPath + ".prov" - if err := os.WriteFile(provFile, []byte(sig), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(sig), 0o644); err != nil { os.Remove(tarballPath) return err } diff --git a/pkg/cmd/plugin_package_test.go b/pkg/cmd/plugin_package_test.go index 7d97562f8..b5ecf2bf1 100644 --- a/pkg/cmd/plugin_package_test.go +++ b/pkg/cmd/plugin_package_test.go @@ -43,12 +43,12 @@ func TestPluginPackageWithoutSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatal(err) } @@ -94,12 +94,12 @@ func TestPluginPackageDefaultRequiresSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatal(err) } @@ -131,12 +131,12 @@ func TestPluginPackageSigningFailure(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatal(err) } diff --git a/pkg/cmd/plugin_uninstall_test.go b/pkg/cmd/plugin_uninstall_test.go index 93d4dc8a8..f715b09c8 100644 --- a/pkg/cmd/plugin_uninstall_test.go +++ b/pkg/cmd/plugin_uninstall_test.go @@ -39,7 +39,7 @@ func TestPluginUninstallCleansUpVersionedFiles(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(pluginsDir, pluginName) - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatal(err) } @@ -49,7 +49,7 @@ version: 1.2.3 description: Test plugin command: $HELM_PLUGIN_DIR/test-plugin ` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644); err != nil { t.Fatal(err) } @@ -58,14 +58,14 @@ command: $HELM_PLUGIN_DIR/test-plugin provFile := filepath.Join(pluginsDir, "test-plugin-1.2.3.tgz.prov") otherVersionTarball := filepath.Join(pluginsDir, "test-plugin-2.0.0.tgz") - if err := os.WriteFile(tarballFile, []byte("fake tarball"), 0644); err != nil { + if err := os.WriteFile(tarballFile, []byte("fake tarball"), 0o644); err != nil { t.Fatal(err) } - if err := os.WriteFile(provFile, []byte("fake provenance"), 0644); err != nil { + if err := os.WriteFile(provFile, []byte("fake provenance"), 0o644); err != nil { t.Fatal(err) } // Create another version that should NOT be removed - if err := os.WriteFile(otherVersionTarball, []byte("other version"), 0644); err != nil { + if err := os.WriteFile(otherVersionTarball, []byte("other version"), 0o644); err != nil { t.Fatal(err) } diff --git a/pkg/cmd/plugin_verify_test.go b/pkg/cmd/plugin_verify_test.go index e631814dd..4ce664c0c 100644 --- a/pkg/cmd/plugin_verify_test.go +++ b/pkg/cmd/plugin_verify_test.go @@ -102,7 +102,7 @@ func TestPluginVerifyCmd_InvalidProvenance(t *testing.T) { // Create invalid .prov file provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("invalid provenance"), 0644); err != nil { + if err := os.WriteFile(provFile, []byte("invalid provenance"), 0o644); err != nil { t.Fatal(err) } defer os.Remove(provFile) @@ -178,12 +178,12 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0755); err != nil { + if err := os.MkdirAll(pluginDir, 0o755); err != nil { t.Fatalf("Failed to create plugin directory: %v", err) } // Use the same plugin YAML as other cmd tests - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0644); err != nil { + if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { t.Fatalf("Failed to create plugin.yaml: %v", err) } @@ -243,7 +243,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0644); err != nil { + if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { t.Fatalf("Failed to create provenance file: %v", err) } } @@ -256,7 +256,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0644); err != nil { + if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { t.Fatalf("Failed to create test keyring: %v", err) } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index 511061dcd..e1b3e8134 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -229,7 +229,7 @@ func TestPullCmd(t *testing.T) { // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182 if tt.existFile != "" { file := filepath.Join(outdir, tt.existFile) - if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil { t.Fatal(err) } _, err := os.Create(file) @@ -239,7 +239,7 @@ func TestPullCmd(t *testing.T) { } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0755) + err := os.MkdirAll(file, 0o755) if err != nil { t.Fatal(err) } @@ -306,7 +306,7 @@ func runPullTests(t *testing.T, tests []struct { } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0755) + err := os.MkdirAll(file, 0o755) if err != nil { t.Fatal(err) } diff --git a/pkg/cmd/repo_add_test.go b/pkg/cmd/repo_add_test.go index 8f8e36d75..1290d3862 100644 --- a/pkg/cmd/repo_add_test.go +++ b/pkg/cmd/repo_add_test.go @@ -270,7 +270,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { t.Errorf("unexpected error, got '%v'", err) } - if !strings.Contains(result, fmt.Sprintf("\"%s\" has been added to your repositories", testName)) { + if !strings.Contains(result, fmt.Sprintf("%q has been added to your repositories", testName)) { t.Errorf("Repo was not successfully added. Output: %s", result) } } diff --git a/pkg/cmd/repo_remove.go b/pkg/cmd/repo_remove.go index 330e69d3a..1d0bb1099 100644 --- a/pkg/cmd/repo_remove.go +++ b/pkg/cmd/repo_remove.go @@ -68,7 +68,7 @@ func (o *repoRemoveOptions) run(out io.Writer) error { if !r.Remove(name) { return fmt.Errorf("no repo named %q found", name) } - if err := r.WriteFile(o.repoFile, 0600); err != nil { + if err := r.WriteFile(o.repoFile, 0o600); err != nil { return err } diff --git a/pkg/cmd/template.go b/pkg/cmd/template.go index bb364231b..ccc1db719 100644 --- a/pkg/cmd/template.go +++ b/pkg/cmd/template.go @@ -239,7 +239,7 @@ func isTestHook(h *release.Hook) bool { // this duplicate code should be removed. It is added here so that the API // surface area is as minimally impacted as possible in fixing the issue. func writeToFile(outputDir string, name string, data string, appendData bool) error { - outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) + outfileName := outputDir + string(filepath.Separator) + name err := ensureDirectoryForFile(outfileName) if err != nil { @@ -265,7 +265,7 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er func createOrOpenFile(filename string, appendData bool) (*os.File, error) { if appendData { - return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600) + return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0o600) } return os.Create(filename) } @@ -277,5 +277,5 @@ func ensureDirectoryForFile(file string) error { return err } - return os.MkdirAll(baseDir, 0755) + return os.MkdirAll(baseDir, 0o755) } diff --git a/pkg/downloader/cache.go b/pkg/downloader/cache.go index 92d477e49..539e7a640 100644 --- a/pkg/downloader/cache.go +++ b/pkg/downloader/cache.go @@ -78,11 +78,11 @@ func (c *DiskCache) Get(key [sha256.Size]byte, cacheType string) (string, error) func (c *DiskCache) Put(key [sha256.Size]byte, data io.Reader, cacheType string) (string, error) { // TODO: verify the key and digest of the key are the same. p := c.fileName(key, cacheType) - if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { slog.Error("failed to create cache directory") return p, err } - return p, fileutil.AtomicWriteFile(p, data, 0644) + return p, fileutil.AtomicWriteFile(p, data, 0o644) } // fileName generates the filename in a structured manner where the first part is the diff --git a/pkg/downloader/cache_test.go b/pkg/downloader/cache_test.go index 340c77aba..7d7fb3059 100644 --- a/pkg/downloader/cache_test.go +++ b/pkg/downloader/cache_test.go @@ -105,7 +105,7 @@ func TestDiskCache_PutAndGet(t *testing.T) { t.Run("GetDirectory", func(t *testing.T) { dirKey := sha256.Sum256([]byte("i am a directory")) dirPath := cache.fileName(dirKey, CacheChart) - err := os.MkdirAll(dirPath, 0755) + err := os.MkdirAll(dirPath, 0o755) require.NoError(t, err) _, err = cache.Get(dirKey, CacheChart) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 22c6c71a3..4a13fc5ed 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -165,7 +165,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven // Use PlatformAtomicWriteFile to handle platform-specific concurrency concerns // (Windows requires locking to avoid "Access Denied" errors when multiple // processes write the same file) - if err := fileutil.PlatformAtomicWriteFile(destfile, data, 0644); err != nil { + if err := fileutil.PlatformAtomicWriteFile(destfile, data, 0o644); err != nil { return destfile, nil, err } @@ -197,7 +197,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven provfile := destfile + ".prov" // Use PlatformAtomicWriteFile for the provenance file as well - if err := fileutil.PlatformAtomicWriteFile(provfile, body, 0644); err != nil { + if err := fileutil.PlatformAtomicWriteFile(provfile, body, 0o644); err != nil { return destfile, nil, err } @@ -321,7 +321,7 @@ func (c *ChartDownloader) DownloadToCache(ref, version string) (string, *provena // Copy chart to a known location with the right name for verification and then // clean it up. tmpdir := filepath.Dir(filepath.Join(c.ContentCache, "tmp")) - if err := os.MkdirAll(tmpdir, 0755); err != nil { + if err := os.MkdirAll(tmpdir, 0o755); err != nil { return pth, ver, err } tmpfile := filepath.Join(tmpdir, name) diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 8a7514a8e..07b25a1eb 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -417,7 +417,7 @@ func TestDownloadToCache(t *testing.T) { t.Run("download and cache chart", func(t *testing.T) { // Clear cache for this test os.RemoveAll(contentCache) - os.MkdirAll(contentCache, 0755) + os.MkdirAll(contentCache, 0o755) c.Cache = &DiskCache{Root: contentCache} pth, v, err := c.DownloadToCache("test/signtest", "0.1.0") @@ -459,7 +459,7 @@ func TestDownloadToCache(t *testing.T) { t.Run("download and verify", func(t *testing.T) { // Clear cache os.RemoveAll(contentCache) - os.MkdirAll(contentCache, 0755) + os.MkdirAll(contentCache, 0o755) c.Cache = &DiskCache{Root: contentCache} c.Verify = VerifyAlways c.Keyring = "testdata/helm-test-key.pub" diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index ac4f2207e..543f685eb 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -257,7 +257,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { return fmt.Errorf("%q is not a directory", destPath) } } else if errors.Is(err, stdfs.ErrNotExist) { - if err := os.MkdirAll(destPath, 0755); err != nil { + if err := os.MkdirAll(destPath, 0o755); err != nil { return err } } else { @@ -265,7 +265,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { } // Prepare tmpPath - if err := os.MkdirAll(tmpPath, 0755); err != nil { + if err := os.MkdirAll(tmpPath, 0o755); err != nil { return err } defer os.RemoveAll(tmpPath) @@ -378,7 +378,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { } func parseOCIRef(chartRef string) (string, string, error) { - refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:[0-9]{1,5})?[^:]+):(.*)$`) + refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:\d{1,5})?[^:]+):(.*)$`) caps := refTagRegexp.FindStringSubmatch(chartRef) if len(caps) != 4 { return "", "", fmt.Errorf("improperly formatted oci chart reference: %s", chartRef) @@ -866,7 +866,7 @@ func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error { } } - return os.WriteFile(dest, data, 0644) + return os.WriteFile(dest, data, 0o644) } // archive a dep chart from local directory and save it into destPath diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 9e27f183f..aea64a0b5 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -264,7 +264,7 @@ func TestDownloadAll(t *testing.T) { } // create a 'tmpcharts' directory to test #5567 - if err := os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0o755); err != nil { t.Fatal(err) } if err := m.downloadAll([]*chart.Dependency{signDep, localDep}); err != nil { @@ -282,10 +282,10 @@ func TestDownloadAll(t *testing.T) { description: A Helm chart for Kubernetes name: ../bad-local-subchart version: 0.1.0` - if err := os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0755); err != nil { + if err := os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0o755); err != nil { t.Fatal(err) } - err = os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0644) + err = os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0o644) if err != nil { t.Fatal(err) } @@ -735,7 +735,7 @@ func TestWriteLock(t *testing.T) { t.Run("overwrite existing lock file", func(t *testing.T) { dir := t.TempDir() lockfilePath := filepath.Join(dir, "Chart.lock") - assert.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0644)) + assert.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0o644)) err = writeLock(dir, lock, false) assert.NoError(t, err) @@ -748,7 +748,7 @@ func TestWriteLock(t *testing.T) { t.Run("lock file is a symlink", func(t *testing.T) { dir := t.TempDir() dummyFile := filepath.Join(dir, "dummy.txt") - assert.NoError(t, os.WriteFile(dummyFile, []byte("dummy"), 0644)) + assert.NoError(t, os.WriteFile(dummyFile, []byte("dummy"), 0o644)) lockfilePath := filepath.Join(dir, "Chart.lock") assert.NoError(t, os.Symlink(dummyFile, lockfilePath)) @@ -761,7 +761,7 @@ func TestWriteLock(t *testing.T) { t.Run("chart path is not a directory", func(t *testing.T) { dir := t.TempDir() filePath := filepath.Join(dir, "not-a-dir") - assert.NoError(t, os.WriteFile(filePath, []byte("file"), 0644)) + assert.NoError(t, os.WriteFile(filePath, []byte("file"), 0o644)) err = writeLock(filePath, lock, false) assert.Error(t, err) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 4f7fa4590..d304aea7d 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -539,7 +539,7 @@ func (p byPathLen) Less(i, j int) bool { a, b := p[i], p[j] ca, cb := strings.Count(a, "/"), strings.Count(b, "/") if ca == cb { - return strings.Compare(a, b) == -1 + return a < b } return ca < cb } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index f3116d626..57bd255b3 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -569,7 +569,7 @@ func TestHttpClientInsecureSkipVerify(t *testing.T) { g.opts.keyFile = "testdata/client.key" g.opts.insecureSkipVerifyTLS = true transport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", true) - if len(transport.TLSClientConfig.Certificates) <= 0 { + if len(transport.TLSClientConfig.Certificates) == 0 { t.Fatal("transport.TLSClientConfig.Certificates is not present") } } diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index b7d362681..52536dfd2 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -301,12 +301,12 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { dst.Close() // Make the file unreadable - if err := os.Chmod(tempChart, 0000); err != nil { + if err := os.Chmod(tempChart, 0o000); err != nil { t.Fatal(err) } return tempChart, func() { - os.Chmod(tempChart, 0644) // Restore permissions for cleanup + os.Chmod(tempChart, 0o644) // Restore permissions for cleanup } }, href: "oci://localhost:5000/test", @@ -342,7 +342,7 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { dst.Close() // Create provenance file - if err := os.WriteFile(tempProv, []byte("test provenance data"), 0644); err != nil { + if err := os.WriteFile(tempProv, []byte("test provenance data"), 0o644); err != nil { t.Fatal(err) } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 7d7b5a112..a1cf11310 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -36,7 +36,6 @@ import ( _ "github.com/distribution/distribution/v3/registry/auth/token" _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "golang.org/x/crypto/bcrypt" @@ -75,9 +74,9 @@ type TestRegistry struct { func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.WorkspaceDir = testWorkspaceDir err := os.RemoveAll(suite.WorkspaceDir) - require.NoError(suite.T(), err, "no error removing test workspace dir") - err = os.Mkdir(suite.WorkspaceDir, 0700) - require.NoError(suite.T(), err, "no error creating test workspace dir") + suite.Require().NoError(err, "no error removing test workspace dir") + err = os.Mkdir(suite.WorkspaceDir, 0o700) + suite.Require().NoError(err, "no error creating test workspace dir") var out bytes.Buffer @@ -123,7 +122,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) suite.Require().NoError(err, "no error generating bcrypt password for test htpasswd file") htpasswdPath := filepath.Join(suite.WorkspaceDir, testHtpasswdFileBasename) - err = os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0644) + err = os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644) suite.Require().NoError(err, "no error creating test htpasswd file") // Registry config diff --git a/pkg/repo/v1/chartrepo.go b/pkg/repo/v1/chartrepo.go index 09b74d602..c7c4a3e7b 100644 --- a/pkg/repo/v1/chartrepo.go +++ b/pkg/repo/v1/chartrepo.go @@ -109,14 +109,14 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) { fmt.Fprintln(&charts, name) } chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) - os.MkdirAll(filepath.Dir(chartsFile), 0755) + os.MkdirAll(filepath.Dir(chartsFile), 0o755) - fileutil.AtomicWriteFile(chartsFile, bytes.NewReader([]byte(charts.String())), 0644) + fileutil.AtomicWriteFile(chartsFile, bytes.NewReader([]byte(charts.String())), 0o644) // Create the index file in the cache directory fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name)) - os.MkdirAll(filepath.Dir(fname), 0755) - return fname, fileutil.AtomicWriteFile(fname, bytes.NewReader(index), 0644) + os.MkdirAll(filepath.Dir(fname), 0o755) + return fname, fileutil.AtomicWriteFile(fname, bytes.NewReader(index), 0o644) } type findChartInRepoURLOptions struct { diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 9259e5a4d..126be125f 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -548,7 +548,7 @@ func TestIndexWrite(t *testing.T) { } dir := t.TempDir() testpath := filepath.Join(dir, "test") - i.WriteFile(testpath, 0600) + i.WriteFile(testpath, 0o600) got, err := os.ReadFile(testpath) if err != nil { @@ -566,7 +566,7 @@ func TestIndexJSONWrite(t *testing.T) { } dir := t.TempDir() testpath := filepath.Join(dir, "test") - i.WriteJSONFile(testpath, 0600) + i.WriteJSONFile(testpath, 0o600) got, err := os.ReadFile(testpath) if err != nil { diff --git a/pkg/repo/v1/repo.go b/pkg/repo/v1/repo.go index 38d2b0ca1..199b56ed8 100644 --- a/pkg/repo/v1/repo.go +++ b/pkg/repo/v1/repo.go @@ -118,7 +118,7 @@ func (r *File) WriteFile(path string, perm os.FileMode) error { if err != nil { return err } - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } return os.WriteFile(path, data, perm) diff --git a/pkg/repo/v1/repo_test.go b/pkg/repo/v1/repo_test.go index 9b5c54309..960635fc5 100644 --- a/pkg/repo/v1/repo_test.go +++ b/pkg/repo/v1/repo_test.go @@ -202,7 +202,7 @@ func TestWriteFile(t *testing.T) { t.Errorf("failed to create test-file (%v)", err) } defer os.Remove(file.Name()) - if err := sampleRepository.WriteFile(file.Name(), 0600); err != nil { + if err := sampleRepository.WriteFile(file.Name(), 0o600); err != nil { t.Errorf("failed to write file (%v)", err) } diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 00a0832b3..2636755a9 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -237,7 +237,7 @@ func (cfgmaps *ConfigMaps) Delete(key string) (rls release.Releaser, err error) return nil, err } // delete the release - if err = cfgmaps.impl.Delete(context.Background(), key, metav1.DeleteOptions{}); err != nil { + if err := cfgmaps.impl.Delete(context.Background(), key, metav1.DeleteOptions{}); err != nil { return rls, err } return rls, nil diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index 756731ef6..4bc48db23 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -49,7 +49,7 @@ func encodeRelease(rls *rspb.Release) (string, error) { w.Close() return "", err } - if err = w.Close(); err != nil { + if err := w.Close(); err != nil { return "", err } diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index d7892844f..5d65557c5 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -16,6 +16,7 @@ limitations under the License. package strvals import ( + "bytes" "fmt" "strings" "testing" @@ -298,7 +299,7 @@ func TestParseLiteral(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) } } @@ -409,7 +410,7 @@ func TestParseLiteralInto(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.input) } } @@ -471,7 +472,7 @@ func TestParseLiteralNestedLevels(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) } } diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 1dbbd0e1b..a0b72bee3 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -226,7 +226,7 @@ func (t *parser) key(data map[string]any, nestedNameLevel int) (reterr error) { // discard in t.sc the chars of the decoded json value (the number of those characters is returned by InputOffset). var jsonval any dec := json.NewDecoder(strings.NewReader(t.sc.String())) - if err = dec.Decode(&jsonval); err != nil { + if err := dec.Decode(&jsonval); err != nil { return err } set(data, string(k), jsonval) @@ -358,7 +358,7 @@ func (t *parser) listItem(list []any, i, nestedNameLevel int) ([]any, error) { // discard in t.sc the chars of the decoded json value (the number of those characters is returned by InputOffset). var jsonval any dec := json.NewDecoder(strings.NewReader(t.sc.String())) - if err = dec.Decode(&jsonval); err != nil { + if err := dec.Decode(&jsonval); err != nil { return list, err } if list, err = setIndex(list, i, jsonval); err != nil { diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 1a9559236..6d254ca8d 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -16,6 +16,7 @@ limitations under the License. package strvals import ( + "bytes" "fmt" "strings" "testing" @@ -400,7 +401,7 @@ func TestParseSet(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) } } @@ -423,7 +424,7 @@ func TestParseSet(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) } } @@ -534,7 +535,7 @@ func TestParseInto(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.input) } } @@ -567,7 +568,7 @@ func TestParseIntoString(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), input) } } @@ -667,7 +668,7 @@ func TestParseJSON(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.input) } } @@ -697,7 +698,7 @@ func TestParseFile(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), input) } } @@ -728,7 +729,7 @@ func TestParseIntoFile(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), input) } } @@ -797,7 +798,7 @@ func TestParseSetNestedLevels(t *testing.T) { require.NoError(t, err, "Error serializing parsed value") } - if string(y1) != string(y2) { + if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) } } From 9b30076180b8f73bbe25d0f4cd752207154ad0c1 Mon Sep 17 00:00:00 2001 From: LarytheLord Date: Thu, 5 Mar 2026 23:47:34 +0530 Subject: [PATCH 037/161] test(cli): isolate user-agent rest config test from host kubeconfig Signed-off-by: LarytheLord --- pkg/cli/environment_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index 9303389a3..df87b86df 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -18,6 +18,7 @@ package cli import ( "os" + "path/filepath" "strings" "testing" @@ -220,6 +221,30 @@ func TestEnvOrBool(t *testing.T) { func TestUserAgentHeaderInK8sRESTClientConfig(t *testing.T) { defer resetEnv()() + kubeconfigPath := filepath.Join(t.TempDir(), "config") + kubeconfig := `apiVersion: v1 +clusters: +- cluster: + server: https://127.0.0.1:6443 + name: test +contexts: +- context: + cluster: test + user: test-user + name: test +current-context: test +kind: Config +preferences: {} +users: +- name: test-user + user: + token: test-token +` + if err := os.WriteFile(kubeconfigPath, []byte(kubeconfig), 0o600); err != nil { + t.Fatalf("failed to create test kubeconfig: %v", err) + } + t.Setenv("KUBECONFIG", kubeconfigPath) + settings := New() restConfig, err := settings.RESTClientGetter().ToRESTConfig() require.NoError(t, err) From 47bde119597961113d769a9d46a565f448565e7a Mon Sep 17 00:00:00 2001 From: LarytheLord Date: Sun, 8 Mar 2026 18:32:35 +0530 Subject: [PATCH 038/161] test(cli): use t.Cleanup for resetEnv with t.Setenv Signed-off-by: LarytheLord --- pkg/cli/environment_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index df87b86df..2d7851a4f 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -120,7 +120,8 @@ func TestEnvSettings(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer resetEnv()() + cleanup := resetEnv() + t.Cleanup(cleanup) for k, v := range tt.envvars { t.Setenv(k, v) @@ -219,7 +220,8 @@ func TestEnvOrBool(t *testing.T) { } func TestUserAgentHeaderInK8sRESTClientConfig(t *testing.T) { - defer resetEnv()() + cleanup := resetEnv() + t.Cleanup(cleanup) kubeconfigPath := filepath.Join(t.TempDir(), "config") kubeconfig := `apiVersion: v1 From f34ad6c337a53f0d77d1e24b5d1c6cdd1c57bc63 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 07:57:58 +0000 Subject: [PATCH 039/161] chore: fix several checks issues from testifylint Signed-off-by: Matthieu MOREL --- .golangci.yml | 10 - internal/chart/v3/lint/lint_test.go | 3 +- internal/fileutil/fileutil_test.go | 6 +- internal/logging/logging_test.go | 5 +- internal/plugin/loader_test.go | 2 +- internal/plugin/metadata_v1_test.go | 3 +- internal/plugin/runtime_extismv1_test.go | 2 +- .../statusreaders/job_status_reader_test.go | 5 +- .../statusreaders/pod_status_reader_test.go | 5 +- internal/tlsutil/tls_test.go | 7 +- internal/urlutil/urlutil_test.go | 3 +- pkg/action/action_test.go | 40 ++-- pkg/action/dependency_test.go | 4 +- pkg/action/get_metadata_test.go | 8 +- pkg/action/get_values_test.go | 4 +- pkg/action/hooks_test.go | 14 +- pkg/action/install_test.go | 219 ++++++++++-------- pkg/action/list_test.go | 67 +++--- pkg/action/package_test.go | 5 +- pkg/action/pull_test.go | 4 +- pkg/action/registry_login_test.go | 11 +- pkg/action/release_testing_test.go | 3 +- pkg/action/rollback_test.go | 3 +- pkg/action/uninstall_test.go | 33 +-- pkg/action/upgrade_test.go | 119 +++++----- pkg/action/validate_test.go | 43 ++-- pkg/chart/common/util/coalesce_test.go | 16 +- pkg/chart/v2/lint/lint_test.go | 3 +- pkg/cli/values/options_test.go | 2 +- pkg/cmd/helpers_test.go | 4 +- pkg/cmd/history_test.go | 2 +- pkg/downloader/cache_test.go | 2 +- pkg/downloader/manager_test.go | 35 +-- pkg/engine/funcs_test.go | 6 +- pkg/kube/client_test.go | 6 +- pkg/kube/statuswait_test.go | 30 +-- pkg/kube/wait_test.go | 5 +- pkg/postrenderer/postrenderer_test.go | 10 +- pkg/registry/chart_test.go | 2 +- pkg/registry/client_scope_test.go | 20 +- pkg/registry/reference_test.go | 15 +- pkg/registry/registry_test.go | 4 +- pkg/release/common_test.go | 12 +- pkg/storage/driver/memory_test.go | 4 +- pkg/storage/storage_test.go | 24 +- 45 files changed, 449 insertions(+), 381 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 518e47052..8c28a6c46 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -139,16 +139,6 @@ linters: - models testifylint: - disable: - - encoded-compare - - equal-values - - expected-actual - - float-compare - - go-require - - nil-compare - - require-error - - suite-dont-use-pkg - - suite-extra-assert-call # Intentionally enable all testifylint rules so new checks are adopted automatically. enable-all: true diff --git a/internal/chart/v3/lint/lint_test.go b/internal/chart/v3/lint/lint_test.go index afacb8052..6a2558fe0 100644 --- a/internal/chart/v3/lint/lint_test.go +++ b/internal/chart/v3/lint/lint_test.go @@ -22,6 +22,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/chart/v3/lint/support" chartutil "helm.sh/helm/v4/internal/chart/v3/util" @@ -126,7 +127,7 @@ func TestBadCrdFileV3(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) - assert.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") + require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go index c78f70a3d..9c997fcd3 100644 --- a/internal/fileutil/fileutil_test.go +++ b/internal/fileutil/fileutil_test.go @@ -38,7 +38,7 @@ func TestAtomicWriteFile(t *testing.T) { mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) - assert.NoError(t, err) + require.NoError(t, err) got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -71,7 +71,7 @@ func TestAtomicWriteFile_EmptyContent(t *testing.T) { mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) - assert.NoError(t, err, "AtomicWriteFile error with empty content") + require.NoError(t, err, "AtomicWriteFile error with empty content") got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -90,7 +90,7 @@ func TestAtomicWriteFile_LargeContent(t *testing.T) { mode := os.FileMode(0o644) err := AtomicWriteFile(testpath, reader, mode) - assert.NoError(t, err, "AtomicWriteFile error with large content") + require.NoError(t, err, "AtomicWriteFile error with large content") got, err := os.ReadFile(testpath) require.NoError(t, err) diff --git a/internal/logging/logging_test.go b/internal/logging/logging_test.go index d22a47a31..83979e9db 100644 --- a/internal/logging/logging_test.go +++ b/internal/logging/logging_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestLogHolder_Logger(t *testing.T) { @@ -198,7 +199,7 @@ func TestDebugCheckHandler_Handle(t *testing.T) { record := slog.NewRecord(time.Now(), slog.LevelInfo, "test message", 0) err := handler.Handle(t.Context(), record) - assert.NoError(t, err) + require.NoError(t, err) assert.Contains(t, buf.String(), "test message") }) @@ -215,7 +216,7 @@ func TestDebugCheckHandler_Handle(t *testing.T) { record := slog.NewRecord(time.Now(), slog.LevelInfo, "context test", 0) err := handler.Handle(ctx, record) - assert.NoError(t, err) + require.NoError(t, err) assert.Contains(t, buf.String(), "context test") }) } diff --git a/internal/plugin/loader_test.go b/internal/plugin/loader_test.go index d6ca472f3..cb0de968d 100644 --- a/internal/plugin/loader_test.go +++ b/internal/plugin/loader_test.go @@ -118,7 +118,7 @@ func TestLoadDir(t *testing.T) { require.NoError(t, err, "error loading plugin from %s", tc.dirname) assert.Equal(t, tc.dirname, plug.Dir()) - assert.EqualValues(t, tc.expect, plug.Metadata()) + assert.Equal(t, tc.expect, plug.Metadata()) }) } } diff --git a/internal/plugin/metadata_v1_test.go b/internal/plugin/metadata_v1_test.go index 17a02dac0..21a78549e 100644 --- a/internal/plugin/metadata_v1_test.go +++ b/internal/plugin/metadata_v1_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMetadataV1ValidateVersion(t *testing.T) { @@ -78,7 +79,7 @@ func TestMetadataV1ValidateVersion(t *testing.T) { m := base() m.Version = tc.version err := m.Validate() - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), tc.errMsg) }) } diff --git a/internal/plugin/runtime_extismv1_test.go b/internal/plugin/runtime_extismv1_test.go index 9451c693b..290d418ea 100644 --- a/internal/plugin/runtime_extismv1_test.go +++ b/internal/plugin/runtime_extismv1_test.go @@ -71,7 +71,7 @@ func TestRuntimeExtismV1InvokePlugin(t *testing.T) { p, err := r.CreatePlugin(pr.Dir, &pr.Metadata) - assert.NoError(t, err, "expected no error creating plugin") + require.NoError(t, err, "expected no error creating plugin") assert.NotNil(t, p, "expected plugin to be created") output, err := p.Invoke(t.Context(), &Input{ diff --git a/internal/statusreaders/job_status_reader_test.go b/internal/statusreaders/job_status_reader_test.go index 6e9ed5a79..fff0fcf3f 100644 --- a/internal/statusreaders/job_status_reader_test.go +++ b/internal/statusreaders/job_status_reader_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -107,9 +108,9 @@ func TestJobConditions(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() us, err := toUnstructured(t, tc.job) - assert.NoError(t, err) + require.NoError(t, err) result, err := jobConditions(us) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tc.expectedStatus, result.Status) }) } diff --git a/internal/statusreaders/pod_status_reader_test.go b/internal/statusreaders/pod_status_reader_test.go index ba0d1f1bb..76fb77afe 100644 --- a/internal/statusreaders/pod_status_reader_test.go +++ b/internal/statusreaders/pod_status_reader_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -102,9 +103,9 @@ func TestPodConditions(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() us, err := toUnstructured(t, tc.pod) - assert.NoError(t, err) + require.NoError(t, err) result, err := podConditions(us) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tc.expectedStatus, result.Status) }) } diff --git a/internal/tlsutil/tls_test.go b/internal/tlsutil/tls_test.go index 324b00969..b1b0f7d85 100644 --- a/internal/tlsutil/tls_test.go +++ b/internal/tlsutil/tls_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -51,7 +50,7 @@ func TestNewTLSConfig(t *testing.T) { WithCertKeyPairFiles(certFile, keyFile), WithCAFile(caCertFile), ) - assert.NoError(t, err) + require.NoError(t, err) require.Len(t, cfg.Certificates, 1) require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") @@ -62,7 +61,7 @@ func TestNewTLSConfig(t *testing.T) { WithInsecureSkipVerify(insecureSkipTLSVerify), WithCAFile(caCertFile), ) - assert.NoError(t, err) + require.NoError(t, err) require.Empty(t, cfg.Certificates) require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") @@ -74,7 +73,7 @@ func TestNewTLSConfig(t *testing.T) { WithInsecureSkipVerify(insecureSkipTLSVerify), WithCertKeyPairFiles(certFile, keyFile), ) - assert.NoError(t, err) + require.NoError(t, err) require.Len(t, cfg.Certificates, 1) require.False(t, cfg.InsecureSkipVerify, "insecure skip verify mismatch, expecting false") diff --git a/internal/urlutil/urlutil_test.go b/internal/urlutil/urlutil_test.go index d6b3f5256..27a646b58 100644 --- a/internal/urlutil/urlutil_test.go +++ b/internal/urlutil/urlutil_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestURLJoin(t *testing.T) { @@ -36,7 +37,7 @@ func TestURLJoin(t *testing.T) { for _, tt := range tests { got, err := URLJoin(tt.url, tt.paths...) - assert.NoError(t, err, tt.name) + require.NoError(t, err, tt.name) assert.Equal(t, tt.expect, got, tt.name) } } diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index ecf160500..045fa7d1e 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -358,10 +358,10 @@ func TestConfiguration_Init(t *testing.T) { actualErr := cfg.Init(nil, "default", tt.helmDriver) if tt.expectErr { - assert.Error(t, actualErr) + require.Error(t, actualErr) assert.Contains(t, actualErr.Error(), tt.errMsg) } else { - assert.NoError(t, actualErr) + require.NoError(t, actualErr) assert.IsType(t, tt.expectedDriverType, cfg.Releases.Driver) } }) @@ -1575,10 +1575,10 @@ data: merged, err := annotateAndMerge(tt.files) if tt.expectedError != "" { - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), tt.expectedError) } else { - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, merged) assert.Equal(t, tt.expected, merged) } @@ -1738,10 +1738,10 @@ data: files, err := splitAndDeannotate(tt.input, "test") if tt.expectedError != "" { - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), tt.expectedError) } else { - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, files, len(tt.expectedFiles)) for expectedFile, expectedContent := range tt.expectedFiles { @@ -1827,7 +1827,7 @@ func TestRenderResources_PostRenderer_Success(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, hooks) assert.NotNil(t, buf) assert.Empty(t, notes) @@ -1874,7 +1874,7 @@ func TestRenderResources_PostRenderer_Error(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "error while running post render on files") } @@ -1902,7 +1902,7 @@ func TestRenderResources_PostRenderer_MergeError(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "error merging manifests") } @@ -1924,7 +1924,7 @@ func TestRenderResources_PostRenderer_SplitError(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "error while parsing post rendered output: error parsing YAML: MalformedYAMLError:") } @@ -1945,7 +1945,7 @@ func TestRenderResources_PostRenderer_Integration(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, hooks) assert.NotNil(t, buf) assert.Empty(t, notes) // Notes should be empty for this test @@ -1984,7 +1984,7 @@ func TestRenderResources_NoPostRenderer(t *testing.T) { nil, false, false, false, PostRenderStrategyCombined, ) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, hooks) assert.NotNil(t, buf) assert.Empty(t, notes) @@ -2045,7 +2045,7 @@ spec: mockPR, false, false, false, PostRenderStrategySeparate, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, hooks, 1) assert.Equal(t, "my-app", hooks[0].Name) assert.Contains(t, buf.String(), "kind: Deployment") @@ -2087,7 +2087,7 @@ metadata: mockPR, false, false, false, PostRenderStrategyCombined, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 1, calls, "combined strategy should invoke the post-renderer exactly once") assert.Contains(t, lastInput, "hook-cm") assert.Contains(t, lastInput, "template-cm") @@ -2123,7 +2123,7 @@ metadata: mockPR, false, false, false, PostRenderStrategy(""), ) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 1, calls, "unset strategy must preserve backwards-compatible combined behavior") } @@ -2157,7 +2157,7 @@ metadata: mockPR, false, false, false, PostRenderStrategySeparate, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, inputs, 2, "separate strategy should invoke the post-renderer twice when both hooks and templates exist") for _, in := range inputs { hasHook := strings.Contains(in, "hook-cm") @@ -2191,7 +2191,7 @@ metadata: mockPR, false, false, false, PostRenderStrategySeparate, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 1, calls, "separate strategy should skip the empty hook group and invoke the post-renderer only once") } @@ -2225,7 +2225,7 @@ metadata: mockPR, false, false, false, PostRenderStrategyNoHooks, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, inputs, 1, "nohooks strategy should invoke the post-renderer exactly once (for templates only)") assert.NotContains(t, inputs[0], "hook-cm", "hooks must not be sent to the post-renderer") assert.Contains(t, inputs[0], "template-cm", "templates must be sent to the post-renderer") @@ -2262,7 +2262,7 @@ metadata: mockPR, false, false, false, PostRenderStrategyNoHooks, ) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 0, calls, "nohooks strategy should not invoke the post-renderer when the chart only has hooks") } @@ -2284,7 +2284,7 @@ metadata: mockPR, false, false, false, PostRenderStrategy("bogus"), ) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "unknown post-render strategy") assert.Contains(t, err.Error(), "bogus") } diff --git a/pkg/action/dependency_test.go b/pkg/action/dependency_test.go index 3899c20fc..25664b98c 100644 --- a/pkg/action/dependency_test.go +++ b/pkg/action/dependency_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -118,13 +119,14 @@ func TestStatArchiveForStatus(t *testing.T) { } is := assert.New(t) + req := require.New(t) lilithpath := filepath.Join(chartpath, "lilith-1.2.3.tgz") is.Empty(statArchiveForStatus(lilithpath, dep)) // save the chart (version 0.1.0, because that is the default) where, err := chartutil.Save(lilith, chartpath) - is.NoError(err) + req.NoError(err) // Should get "wrong version" because we asked for 1.2.3 and got 0.1.0 is.Equal("wrong version", statArchiveForStatus(where, dep)) diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index b488abf64..ee0bd84a0 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -443,7 +443,7 @@ func TestGetMetadata_Run_UnreachableKubeClient(t *testing.T) { client := NewGetMetadata(cfg) _, err := client.Run("test-release") - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "connection refused") } @@ -452,7 +452,7 @@ func TestGetMetadata_Run_ReleaseNotFound(t *testing.T) { client := NewGetMetadata(cfg) _, err := client.Run("non-existent-release") - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "not found") } @@ -648,10 +648,10 @@ func TestGetMetadata_Labels(t *testing.T) { metaGetter := NewGetMetadata(actionConfigFixture(t)) err := metaGetter.cfg.Releases.Create(rel) - assert.NoError(t, err) + require.NoError(t, err) metadata, err := metaGetter.Run(rel.Name) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, metadata.Name, rel.Name) assert.Equal(t, metadata.Labels, customLabels) diff --git a/pkg/action/get_values_test.go b/pkg/action/get_values_test.go index c4cbdf2d5..ce937b234 100644 --- a/pkg/action/get_values_test.go +++ b/pkg/action/get_values_test.go @@ -177,7 +177,7 @@ func TestGetValues_Run_UnreachableKubeClient(t *testing.T) { client := NewGetValues(cfg) _, err := client.Run("test-release") - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "connection refused") } @@ -186,7 +186,7 @@ func TestGetValues_Run_ReleaseNotFound(t *testing.T) { client := NewGetValues(cfg) _, err := client.Run("non-existent-release") - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "not found") } diff --git a/pkg/action/hooks_test.go b/pkg/action/hooks_test.go index b017b1f11..20442af13 100644 --- a/pkg/action/hooks_test.go +++ b/pkg/action/hooks_test.go @@ -28,6 +28,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/yaml" @@ -177,6 +178,7 @@ func runInstallForHooksWithSuccess(t *testing.T, manifest, expectedNamespace str expectedOutput = "attempted to output logs for namespace: " + expectedNamespace } is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "failed-hooks" outBuffer := &bytes.Buffer{} @@ -190,9 +192,9 @@ func runInstallForHooksWithSuccess(t *testing.T, manifest, expectedNamespace str vals := map[string]any{} resi, err := instAction.Run(buildChartWithTemplates(templates), vals) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Equal(expectedOutput, outBuffer.String()) is.Equal(rcommon.StatusDeployed, res.Info.Status) } @@ -204,6 +206,7 @@ func runInstallForHooksWithFailure(t *testing.T, manifest, expectedNamespace str expectedOutput = "attempted to output logs for namespace: " + expectedNamespace } is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "failed-hooks" failingClient := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -220,9 +223,9 @@ func runInstallForHooksWithFailure(t *testing.T, manifest, expectedNamespace str vals := map[string]any{} resi, err := instAction.Run(buildChartWithTemplates(templates), vals) - is.Error(err) + req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "failed pre-install") is.Equal(expectedOutput, outBuffer.String()) is.Equal(rcommon.StatusFailed, res.Info.Status) @@ -447,6 +450,7 @@ func TestConfiguration_hookSetDeletePolicy(t *testing.T) { func TestExecHook_WaitOptionsPassedDownstream(t *testing.T) { is := assert.New(t) + req := require.New(t) failer := &kubefake.FailingKubeClient{ PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, @@ -487,7 +491,7 @@ data: waitOptions := []kube.WaitOption{kube.WithWaitContext(ctx)} err := configuration.execHook(rel, release.HookPreInstall, kube.StatusWatcherStrategy, waitOptions, 600, false) - is.NoError(err) + req.NoError(err) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 705a8e11d..28f989524 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -189,25 +189,25 @@ func TestInstallRelease(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) - is.Equal(res.Name, "test-install-release", "Expected release name.") - is.Equal(res.Namespace, "spaced") + req.NoError(err) + is.Equal("test-install-release", res.Name, "Expected release name.") + is.Equal("spaced", res.Namespace) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) is.Len(rel.Hooks, 1) - is.Equal(rel.Hooks[0].Manifest, manifestWithHook) - is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall) - is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete") + is.Equal(manifestWithHook, rel.Hooks[0].Manifest) + is.Equal(release.HookPostInstall, rel.Hooks[0].Events[0]) + is.Equal(release.HookPreDelete, rel.Hooks[0].Events[1], "Expected event 0 is pre-delete") is.NotEmpty(res.Manifest) is.NotEmpty(rel.Manifest) is.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world") - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) // Detecting previous bug where context termination after successful release // caused release to fail. @@ -216,8 +216,8 @@ func TestInstallRelease(t *testing.T) { lastRelease, err := instAction.cfg.Releases.Last(rel.Name) req.NoError(err) lrel, err := releaserToV1Release(lastRelease) - is.NoError(err) - is.Equal(lrel.Info.Status, rcommon.StatusDeployed) + req.NoError(err) + is.Equal(rcommon.StatusDeployed, lrel.Info.Status) } func TestInstallReleaseWithTakeOwnership_ResourceNotOwned(t *testing.T) { @@ -231,6 +231,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceNotOwned(t *testing.T) { // "Client{Namespace: namespace, kubeClient: k8sfake.NewClientset()}" is := assert.New(t) + req := require.New(t) // Resource list from cluster is NOT owned by helm chart config := actionConfigFixtureWithDummyResources(t, createDummyResourceList(false)) @@ -241,19 +242,20 @@ func TestInstallReleaseWithTakeOwnership_ResourceNotOwned(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) } func TestInstallReleaseWithTakeOwnership_ResourceOwned(t *testing.T) { is := assert.New(t) + req := require.New(t) // Resource list from cluster is owned by helm chart config := actionConfigFixtureWithDummyResources(t, createDummyResourceList(true)) @@ -264,29 +266,31 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwned(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) } func TestInstallReleaseWithTakeOwnership_ResourceOwnedNoFlag(t *testing.T) { is := assert.New(t) + req := require.New(t) // Resource list from cluster is NOT owned by helm chart config := actionConfigFixtureWithDummyResources(t, createDummyResourceList(false)) instAction := installActionWithConfig(config) _, err := instAction.Run(buildChart(), nil) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "unable to continue with install") } func TestInstallReleaseWithValues(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) userVals := map[string]any{ "nestedKey": map[string]any{ @@ -303,20 +307,20 @@ func TestInstallReleaseWithValues(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) - is.Equal(res.Name, "test-install-release", "Expected release name.") - is.Equal(res.Namespace, "spaced") + req.NoError(err) + is.Equal("test-install-release", res.Name, "Expected release name.") + is.Equal("spaced", res.Namespace) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) is.Len(rel.Hooks, 1) - is.Equal(rel.Hooks[0].Manifest, manifestWithHook) - is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall) - is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete") + is.Equal(manifestWithHook, rel.Hooks[0].Manifest) + is.Equal(release.HookPostInstall, rel.Hooks[0].Events[0]) + is.Equal(release.HookPreDelete, rel.Hooks[0].Events[1], "Expected event 0 is pre-delete") is.NotEmpty(res.Manifest) is.NotEmpty(rel.Manifest) @@ -338,6 +342,7 @@ func TestInstallRelease_NoName(t *testing.T) { func TestInstallRelease_WithNotes(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]any{} @@ -346,29 +351,30 @@ func TestInstallRelease_WithNotes(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) - is.Equal(res.Name, "with-notes") - is.Equal(res.Namespace, "spaced") + is.Equal("with-notes", res.Name) + is.Equal("spaced", res.Namespace) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) is.Len(rel.Hooks, 1) - is.Equal(rel.Hooks[0].Manifest, manifestWithHook) - is.Equal(rel.Hooks[0].Events[0], release.HookPostInstall) - is.Equal(rel.Hooks[0].Events[1], release.HookPreDelete, "Expected event 0 is pre-delete") + is.Equal(manifestWithHook, rel.Hooks[0].Manifest) + is.Equal(release.HookPostInstall, rel.Hooks[0].Events[0]) + is.Equal(release.HookPreDelete, rel.Hooks[0].Events[1], "Expected event 0 is pre-delete") is.NotEmpty(res.Manifest) is.NotEmpty(rel.Manifest) is.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world") - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) - is.Equal(rel.Info.Notes, "note here") + is.Equal("note here", rel.Info.Notes) } func TestInstallRelease_WithNotesRendered(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]any{} @@ -377,21 +383,22 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) expectedNotes := "got-" + res.Name is.Equal(expectedNotes, rel.Info.Notes) - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) } func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { // Regression: Make sure that the child's notes don't override the parent's is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]any{} @@ -400,20 +407,21 @@ func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) is.Equal("with-notes", rel.Name) is.Equal("parent", rel.Info.Notes) - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) } func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { // Regression: Make sure that the child's notes don't override the parent's is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "with-notes" instAction.SubNotes = true @@ -423,23 +431,24 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) - is.NoError(err) + req.NoError(err) rel, err := releaserToV1Release(r) - is.NoError(err) + req.NoError(err) is.Equal("with-notes", rel.Name) // test run can return as either 'parent\nchild' or 'child\nparent' if !strings.Contains(rel.Info.Notes, "parent") && !strings.Contains(rel.Info.Notes, "child") { t.Fatalf("Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes) } - is.Equal(rel.Info.Description, "Install complete") + is.Equal("Install complete", rel.Info.Description) } func TestInstallRelease_DryRunClient(t *testing.T) { for _, dryRunStrategy := range []DryRunStrategy{DryRunClient, DryRunServer} { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.DryRunStrategy = dryRunStrategy @@ -449,7 +458,7 @@ func TestInstallRelease_DryRunClient(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Manifest, "---\n# Source: hello/templates/hello\nhello: world") is.Contains(res.Manifest, "---\n# Source: hello/templates/goodbye\ngoodbye: world") @@ -458,15 +467,16 @@ func TestInstallRelease_DryRunClient(t *testing.T) { is.NotContains(res.Manifest, "empty") _, err = instAction.cfg.Releases.Get(res.Name, res.Version) - is.Error(err) + req.Error(err) is.Len(res.Hooks, 1) is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "expect hook to not be marked as run") - is.Equal(res.Info.Description, "Dry run complete") + is.Equal("Dry run complete", res.Info.Description) } } func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) // First perform a normal dry-run with the secret and confirm its presence. @@ -477,12 +487,12 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret") _, err = instAction.cfg.Releases.Get(res.Name, res.Version) - is.Error(err) - is.Equal(res.Info.Description, "Dry run complete") + req.Error(err) + is.Equal("Dry run complete", res.Info.Description) // Perform a dry-run where the secret should not be present instAction.HideSecret = true @@ -492,13 +502,13 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { t.Fatalf("Failed install: %s", err) } res2, err := releaserToV1Release(res2i) - is.NoError(err) + req.NoError(err) is.NotContains(res2.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret") _, err = instAction.cfg.Releases.Get(res2.Name, res2.Version) - is.Error(err) - is.Equal(res2.Info.Description, "Dry run complete") + req.Error(err) + is.Equal("Dry run complete", res2.Info.Description) // Ensure there is an error when HideSecret True but not in a dry-run mode instAction.DryRunStrategy = DryRunNone @@ -512,6 +522,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { // Regression test for #7955 func TestInstallRelease_DryRun_Lookup(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.DryRunStrategy = DryRunNone vals := map[string]any{} @@ -528,7 +539,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Manifest, "goodbye: map[]") } @@ -550,6 +561,7 @@ func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { func TestInstallRelease_NoHooks(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.DisableHooks = true instAction.ReleaseName = "no-hooks" @@ -561,13 +573,14 @@ func TestInstallRelease_NoHooks(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "hooks should not run with no-hooks") } func TestInstallRelease_FailedHooks(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "failed-hooks" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -578,9 +591,9 @@ func TestInstallRelease_FailedHooks(t *testing.T) { vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - is.Error(err) + req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "failed post-install") is.Empty(outBuffer.String()) is.Equal(rcommon.StatusFailed, res.Info.Status) @@ -588,48 +601,51 @@ func TestInstallRelease_FailedHooks(t *testing.T) { func TestInstallRelease_ReplaceRelease(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.Replace = true rel := releaseStub() rel.Info.Status = rcommon.StatusUninstalled - require.NoError(t, instAction.cfg.Releases.Create(rel)) + req.NoError(instAction.cfg.Releases.Create(rel)) instAction.ReleaseName = rel.Name vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // This should have been auto-incremented is.Equal(2, res.Version) is.Equal(res.Name, rel.Name) r, err := instAction.cfg.Releases.Get(rel.Name, res.Version) - is.NoError(err) + req.NoError(err) getres, err := releaserToV1Release(r) - is.NoError(err) - is.Equal(getres.Info.Status, rcommon.StatusDeployed) + req.NoError(err) + is.Equal(rcommon.StatusDeployed, getres.Info.Status) } func TestInstallRelease_KubeVersion(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) vals := map[string]any{} _, err := instAction.Run(buildChart(withKube(">=0.0.0")), vals) - is.NoError(err) + req.NoError(err) // This should fail for a few hundred years instAction.ReleaseName = "should-fail" vals = map[string]any{} _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "chart requires kubeVersion: >=99.0.0 which is incompatible with Kubernetes v1.20.") } func TestInstallRelease_Wait(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "come-fail-away" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -641,16 +657,17 @@ func TestInstallRelease_Wait(t *testing.T) { goroutines := instAction.getGoroutineCount() resi, err := instAction.Run(buildChart(), vals) - is.Error(err) + req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "I timed out") - is.Equal(res.Info.Status, rcommon.StatusFailed) + is.Equal(rcommon.StatusFailed, res.Info.Status) is.Equal(goroutines, instAction.getGoroutineCount()) } func TestInstallRelease_Wait_Interrupted(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "interrupted-release" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -665,7 +682,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { goroutines := instAction.getGoroutineCount() _, err := instAction.RunWithContext(ctx, buildChart(), vals) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "context canceled") is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background @@ -674,6 +691,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { } func TestInstallRelease_WaitForJobs(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "come-fail-away" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -684,17 +702,17 @@ func TestInstallRelease_WaitForJobs(t *testing.T) { vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - is.Error(err) + req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "I timed out") - is.Equal(res.Info.Status, rcommon.StatusFailed) + is.Equal(rcommon.StatusFailed, res.Info.Status) } func TestInstallRelease_RollbackOnFailure(t *testing.T) { - is := assert.New(t) - t.Run("rollback-on-failure uninstall succeeds", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "come-fail-away" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -707,19 +725,21 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "I timed out") is.Contains(err.Error(), "rollback-on-failure") res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it isn't in storage anymore _, err = instAction.cfg.Releases.Get(res.Name, res.Version) - is.Error(err) + req.Error(err) is.Equal(err, driver.ErrReleaseNotFound) }) t.Run("rollback-on-failure uninstall fails", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "come-fail-away-with-me" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -730,7 +750,7 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { vals := map[string]any{} _, err := instAction.Run(buildChart(), vals) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "I timed out") is.Contains(err.Error(), "uninstall fail") is.Contains(err.Error(), "an error occurred while uninstalling the release") @@ -738,6 +758,7 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { } func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "interrupted-release" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) @@ -752,16 +773,16 @@ func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { goroutines := instAction.getGoroutineCount() resi, err := instAction.RunWithContext(ctx, buildChart(), vals) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "context canceled") is.Contains(err.Error(), "rollback-on-failure") is.Contains(err.Error(), "uninstalled") res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it isn't in storage anymore _, err = instAction.cfg.Releases.Get(res.Name, res.Version) - is.Error(err) + req.Error(err) is.Equal(err, driver.ErrReleaseNotFound) is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background time.Sleep(10 * time.Second) // wait for goroutine to finish @@ -837,6 +858,7 @@ func TestNameTemplate(t *testing.T) { func TestInstallReleaseOutputDir(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) vals := map[string]any{} @@ -850,16 +872,16 @@ func TestInstallReleaseOutputDir(t *testing.T) { } _, err = os.Stat(filepath.Join(dir, "hello/templates/goodbye")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(dir, "hello/templates/hello")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(dir, "hello/templates/rbac")) - is.NoError(err) + req.NoError(err) test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt") @@ -869,6 +891,7 @@ func TestInstallReleaseOutputDir(t *testing.T) { func TestInstallOutputDirWithReleaseName(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) vals := map[string]any{} @@ -886,16 +909,16 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { } _, err = os.Stat(filepath.Join(newDir, "hello/templates/goodbye")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(newDir, "hello/templates/hello")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials")) - is.NoError(err) + req.NoError(err) _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac")) - is.NoError(err) + req.NoError(err) test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt") @@ -1008,6 +1031,7 @@ func TestNameAndChartGenerateName(t *testing.T) { func TestInstallWithLabels(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.Labels = map[string]string{ "key1": "val1", @@ -1018,7 +1042,7 @@ func TestInstallWithLabels(t *testing.T) { t.Fatalf("Failed install: %s", err) } res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Equal(instAction.Labels, res.Labels) } @@ -1275,6 +1299,7 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.ReleaseName = "wait-options-test" @@ -1289,7 +1314,7 @@ func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { vals := map[string]any{} _, err := instAction.Run(buildChart(), vals) - is.NoError(err) + req.NoError(err) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index 19596dbbb..e7c2770d7 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" kubefake "helm.sh/helm/v4/pkg/kube/fake" ri "helm.sh/helm/v4/pkg/release" @@ -64,7 +65,7 @@ func TestListStates(t *testing.T) { func TestList_Empty(t *testing.T) { lister := NewList(actionConfigFixture(t)) list, err := lister.Run() - assert.NoError(t, err) + require.NoError(t, err) assert.Empty(t, list) } @@ -75,33 +76,36 @@ func newListFixture(t *testing.T) *List { func TestList_OneNamespace(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) makeMeSomeReleases(t, lister.cfg.Releases) list, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Len(list, 3) } func TestList_AllNamespaces(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) makeMeSomeReleases(t, lister.cfg.Releases) lister.AllNamespaces = true lister.SetStateMask() list, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Len(list, 3) } func TestList_Sort(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Sort = ByNameDesc // Other sorts are tested elsewhere makeMeSomeReleases(t, lister.cfg.Releases) l, err := lister.Run() - is.NoError(err) + req.NoError(err) list, err := releaseListToV1List(l) - is.NoError(err) + req.NoError(err) is.Len(list, 3) is.Equal("two", list[0].Name) @@ -111,13 +115,14 @@ func TestList_Sort(t *testing.T) { func TestList_Limit(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Limit = 2 makeMeSomeReleases(t, lister.cfg.Releases) l, err := lister.Run() - is.NoError(err) + req.NoError(err) list, err := releaseListToV1List(l) - is.NoError(err) + req.NoError(err) is.Len(list, 2) // Lex order means one, three, two is.Equal("one", list[0].Name) @@ -126,13 +131,14 @@ func TestList_Limit(t *testing.T) { func TestList_BigLimit(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Limit = 20 makeMeSomeReleases(t, lister.cfg.Releases) l, err := lister.Run() - is.NoError(err) + req.NoError(err) list, err := releaseListToV1List(l) - is.NoError(err) + req.NoError(err) is.Len(list, 3) // Lex order means one, three, two @@ -143,14 +149,15 @@ func TestList_BigLimit(t *testing.T) { func TestList_LimitOffset(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Limit = 2 lister.Offset = 1 makeMeSomeReleases(t, lister.cfg.Releases) l, err := lister.Run() - is.NoError(err) + req.NoError(err) list, err := releaseListToV1List(l) - is.NoError(err) + req.NoError(err) is.Len(list, 2) // Lex order means one, three, two @@ -160,27 +167,29 @@ func TestList_LimitOffset(t *testing.T) { func TestList_LimitOffsetOutOfBounds(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Limit = 2 lister.Offset = 3 // Last item is index 2 makeMeSomeReleases(t, lister.cfg.Releases) list, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Empty(list) lister.Limit = 10 lister.Offset = 1 list, err = lister.Run() - is.NoError(err) + req.NoError(err) is.Len(list, 2) } func TestList_StateMask(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) makeMeSomeReleases(t, lister.cfg.Releases) oner, err := lister.cfg.Releases.Get("one", 1) - is.NoError(err) + req.NoError(err) var one release.Release switch v := oner.(type) { @@ -194,18 +203,18 @@ func TestList_StateMask(t *testing.T) { one.SetStatus(common.StatusUninstalled, "uninstalled") err = lister.cfg.Releases.Update(one) - is.NoError(err) + req.NoError(err) res, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Len(res, 3) ac0, err := ri.NewAccessor(res[0]) - is.NoError(err) + req.NoError(err) ac1, err := ri.NewAccessor(res[1]) - is.NoError(err) + req.NoError(err) ac2, err := ri.NewAccessor(res[2]) - is.NoError(err) + req.NoError(err) is.Equal("one", ac0.Name()) is.Equal("three", ac1.Name()) @@ -213,20 +222,21 @@ func TestList_StateMask(t *testing.T) { lister.StateMask = ListUninstalled res, err = lister.Run() - is.NoError(err) + req.NoError(err) is.Len(res, 1) ac0, err = ri.NewAccessor(res[0]) - is.NoError(err) + req.NoError(err) is.Equal("one", ac0.Name()) lister.StateMask |= ListDeployed res, err = lister.Run() - is.NoError(err) + req.NoError(err) is.Len(res, 3) } func TestList_StateMaskWithStaleRevisions(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.StateMask = ListFailed @@ -234,13 +244,13 @@ func TestList_StateMaskWithStaleRevisions(t *testing.T) { res, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Len(res, 1) // "dirty" release should _not_ be present as most recent // release is deployed despite failed release in past ac0, err := ri.NewAccessor(res[0]) - is.NoError(err) + req.NoError(err) is.Equal("failed", ac0.Name()) } @@ -273,21 +283,22 @@ func makeMeSomeReleasesWithStaleFailure(t *testing.T, store *storage.Storage) { } all, err := store.ListReleases() - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, all, 5, "sanity test: five items added") } func TestList_Filter(t *testing.T) { is := assert.New(t) + req := require.New(t) lister := newListFixture(t) lister.Filter = "th." makeMeSomeReleases(t, lister.cfg.Releases) res, err := lister.Run() - is.NoError(err) + req.NoError(err) is.Len(res, 1) ac0, err := ri.NewAccessor(res[0]) - is.NoError(err) + req.NoError(err) is.Equal("three", ac0.Name()) } @@ -323,7 +334,7 @@ func makeMeSomeReleases(t *testing.T, store *storage.Storage) { } all, err := store.ListReleases() - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, all, 3, "sanity test: three items added") } diff --git a/pkg/action/package_test.go b/pkg/action/package_test.go index ccba4f847..9984b508a 100644 --- a/pkg/action/package_test.go +++ b/pkg/action/package_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/Masterminds/semver/v3" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" @@ -92,8 +93,8 @@ func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { passphrase := "secret-from-stdin" go func() { - _, err = w.WriteString(passphrase + "\n") - require.NoError(t, err) + _, err := w.WriteString(passphrase + "\n") + assert.NoError(t, err) }() for range 4 { diff --git a/pkg/action/pull_test.go b/pkg/action/pull_test.go index ba212973e..7cd5d3e85 100644 --- a/pkg/action/pull_test.go +++ b/pkg/action/pull_test.go @@ -71,8 +71,8 @@ func startLocalServerForTests(t *testing.T, handler http.Handler) (*httptest.Ser return nil, err } handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - _, err = w.Write(fileBytes) - require.NoError(t, err) + _, err := w.Write(fileBytes) + assert.NoError(t, err) }) } diff --git a/pkg/action/registry_login_test.go b/pkg/action/registry_login_test.go index 474118c9f..408f16d84 100644 --- a/pkg/action/registry_login_test.go +++ b/pkg/action/registry_login_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNewRegistryLogin(t *testing.T) { @@ -37,7 +38,7 @@ func TestWithCertFile(t *testing.T) { certFile := "testdata/cert.pem" opt := WithCertFile(certFile) - assert.NoError(t, opt(client)) + require.NoError(t, opt(client)) assert.Equal(t, certFile, client.certFile) } @@ -47,7 +48,7 @@ func TestWithInsecure(t *testing.T) { opt := WithInsecure(true) - assert.NoError(t, opt(client)) + require.NoError(t, opt(client)) assert.True(t, client.insecure) } @@ -58,7 +59,7 @@ func TestWithKeyFile(t *testing.T) { keyFile := "testdata/key.pem" opt := WithKeyFile(keyFile) - assert.NoError(t, opt(client)) + require.NoError(t, opt(client)) assert.Equal(t, keyFile, client.keyFile) } @@ -69,7 +70,7 @@ func TestWithCAFile(t *testing.T) { caFile := "testdata/ca.pem" opt := WithCAFile(caFile) - assert.NoError(t, opt(client)) + require.NoError(t, opt(client)) assert.Equal(t, caFile, client.caFile) } @@ -79,6 +80,6 @@ func TestWithPlainHTTPLogin(t *testing.T) { opt := WithPlainHTTPLogin(true) - assert.NoError(t, opt(client)) + require.NoError(t, opt(client)) assert.True(t, client.plainHTTP) } diff --git a/pkg/action/release_testing_test.go b/pkg/action/release_testing_test.go index 2ec62caf0..d2a365cba 100644 --- a/pkg/action/release_testing_test.go +++ b/pkg/action/release_testing_test.go @@ -147,6 +147,7 @@ func TestReleaseTestingGetPodLogs_SkipNonPodHooks(t *testing.T) { func TestReleaseTesting_WaitOptionsPassedDownstream(t *testing.T) { is := assert.New(t) + req := require.New(t) config := actionConfigFixture(t) // Create a release with a test hook @@ -165,7 +166,7 @@ func TestReleaseTesting_WaitOptionsPassedDownstream(t *testing.T) { failer := config.KubeClient.(*kubefake.FailingKubeClient) _, _, err := client.Run(rel.Name) - is.NoError(err) + req.NoError(err) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index b34adda91..01419341b 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -49,6 +49,7 @@ func TestRollbackRun_UnreachableKubeClient(t *testing.T) { func TestRollback_WaitOptionsPassedDownstream(t *testing.T) { is := assert.New(t) + req := require.New(t) config := actionConfigFixture(t) // Create a deployed release and a second version to roll back to @@ -78,7 +79,7 @@ func TestRollback_WaitOptionsPassedDownstream(t *testing.T) { failer := config.KubeClient.(*kubefake.FailingKubeClient) err := client.Run(rel.Name) - is.NoError(err) + req.NoError(err) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 90f69d639..913ade1a5 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -61,6 +61,7 @@ func TestUninstallRelease_ignoreNotFound(t *testing.T) { } func TestUninstallRelease_deleteRelease(t *testing.T) { is := assert.New(t) + req := require.New(t) unAction := uninstallAction(t) unAction.DisableHooks = true @@ -83,9 +84,9 @@ func TestUninstallRelease_deleteRelease(t *testing.T) { "password": "password" } }` - require.NoError(t, unAction.cfg.Releases.Create(rel)) + req.NoError(unAction.cfg.Releases.Create(rel)) res, err := unAction.Run(rel.Name) - is.NoError(err) + req.NoError(err) expected := `These resources were kept due to the resource policy: [Secret] secret ` @@ -94,6 +95,7 @@ func TestUninstallRelease_deleteRelease(t *testing.T) { func TestUninstallRelease_Wait(t *testing.T) { is := assert.New(t) + req := require.New(t) unAction := uninstallAction(t) unAction.DisableHooks = true @@ -113,16 +115,16 @@ func TestUninstallRelease_Wait(t *testing.T) { "password": "password" } }` - require.NoError(t, unAction.cfg.Releases.Create(rel)) + req.NoError(unAction.cfg.Releases.Create(rel)) failer := unAction.cfg.KubeClient.(*kubefake.FailingKubeClient) failer.WaitForDeleteError = errors.New("U timed out") unAction.cfg.KubeClient = failer resi, err := unAction.Run(rel.Name) - is.Error(err) + req.Error(err) is.Contains(err.Error(), "U timed out") res, err := releaserToV1Release(resi.Release) - is.NoError(err) - is.Equal(res.Info.Status, common.StatusUninstalled) + req.NoError(err) + is.Equal(common.StatusUninstalled, res.Info.Status) } func TestUninstallRelease_Cascade(t *testing.T) { @@ -180,6 +182,7 @@ func TestUninstallRun_UnreachableKubeClient(t *testing.T) { func TestUninstallRelease_OwnershipVerification(t *testing.T) { is := assert.New(t) + req := require.New(t) // Create a buffer to capture log output logBuffer := &bytes.Buffer{} @@ -207,7 +210,7 @@ metadata: meta.helm.sh/release-namespace: default data: key: value` - require.NoError(t, config.Releases.Create(rel)) + req.NoError(config.Releases.Create(rel)) // Create dummy resources with proper ownership metadata labels := map[string]string{ @@ -224,10 +227,10 @@ data: failer.DummyResources = dummyResources resi, err := unAction.Run(rel.Name) - is.NoError(err) + req.NoError(err) is.NotNil(resi) res, err := releaserToV1Release(resi.Release) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusUninstalled, res.Info.Status) // Verify log contains debug message about deleting owned resource @@ -239,6 +242,7 @@ data: func TestUninstallRelease_OwnershipVerification_WithKeepPolicy(t *testing.T) { is := assert.New(t) + req := require.New(t) // Create a buffer to capture log output logBuffer := &bytes.Buffer{} @@ -280,7 +284,7 @@ metadata: meta.helm.sh/release-namespace: default data: key: value` - require.NoError(t, config.Releases.Create(rel)) + req.NoError(config.Releases.Create(rel)) // Create dummy resources - one unowned to test logging dummyResources := kube.ResourceList{ @@ -290,7 +294,7 @@ data: failer.DummyResources = dummyResources res, err := unAction.Run(rel.Name) - is.NoError(err) + req.NoError(err) is.NotNil(res) // Should contain info about kept resources is.Contains(res.Info, "kept due to the resource policy") @@ -303,6 +307,7 @@ data: func TestUninstallRelease_DryRun_OwnershipVerification(t *testing.T) { is := assert.New(t) + req := require.New(t) // Create a buffer to capture log output logBuffer := &bytes.Buffer{} @@ -329,7 +334,7 @@ metadata: meta.helm.sh/release-namespace: default data: key: value` - require.NoError(t, config.Releases.Create(rel)) + req.NoError(config.Releases.Create(rel)) // Create dummy resources - one unowned to test dry-run logging dummyResources := kube.ResourceList{ @@ -339,11 +344,11 @@ data: failer.DummyResources = dummyResources resi, err := unAction.Run(rel.Name) - is.NoError(err) + req.NoError(err) is.NotNil(resi) is.NotNil(resi.Release) res, err := releaserToV1Release(resi.Release) - is.NoError(err) + req.NoError(err) is.Equal("dryrun-ownership", res.Name) // Verify log contains dry-run warning about resources that would be skipped diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index bd020cbdb..7a73c7179 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -66,8 +66,8 @@ func TestUpgradeRelease_Success(t *testing.T) { resi, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) - is.Equal(res.Info.Status, common.StatusDeployed) + req.NoError(err) + is.Equal(common.StatusDeployed, res.Info.Status) done() // Detecting previous bug where context termination after successful release @@ -77,7 +77,7 @@ func TestUpgradeRelease_Success(t *testing.T) { req.NoError(err) lastRelease, err := releaserToV1Release(lastReleasei) req.NoError(err) - is.Equal(lastRelease.Info.Status, common.StatusDeployed) + is.Equal(common.StatusDeployed, lastRelease.Info.Status) } func TestUpgradeRelease_Wait(t *testing.T) { @@ -99,9 +99,9 @@ func TestUpgradeRelease_Wait(t *testing.T) { resi, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "I timed out") - is.Equal(res.Info.Status, common.StatusFailed) + is.Equal(common.StatusFailed, res.Info.Status) } func TestUpgradeRelease_WaitForJobs(t *testing.T) { @@ -124,9 +124,9 @@ func TestUpgradeRelease_WaitForJobs(t *testing.T) { resi, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "I timed out") - is.Equal(res.Info.Status, common.StatusFailed) + is.Equal(common.StatusFailed, res.Info.Status) } func TestUpgradeRelease_CleanupOnFail(t *testing.T) { @@ -151,22 +151,21 @@ func TestUpgradeRelease_CleanupOnFail(t *testing.T) { req.Error(err) is.NotContains(err.Error(), "unable to cleanup resources") res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "I timed out") - is.Equal(res.Info.Status, common.StatusFailed) + is.Equal(common.StatusFailed, res.Info.Status) } func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { - is := assert.New(t) - req := require.New(t) - t.Run("rollback-on-failure rollback succeeds", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) rel := releaseStub() rel.Name = "nuketown" rel.Info.Status = common.StatusDeployed - require.NoError(t, upAction.cfg.Releases.Create(rel)) + req.NoError(upAction.cfg.Releases.Create(rel)) failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient) // We can't make Update error because then the rollback won't work @@ -180,18 +179,20 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { is.Contains(err.Error(), "arming key removed") is.Contains(err.Error(), "rollback-on-failure") res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 3) - is.NoError(err) + req.NoError(err) updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) // Should have rolled back to the previous - is.Equal(updatedRes.Info.Status, common.StatusDeployed) + is.Equal(common.StatusDeployed, updatedRes.Info.Status) }) t.Run("rollback-on-failure uninstall fails", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) rel := releaseStub() rel.Name = "fallout" @@ -212,9 +213,9 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { } func TestUpgradeRelease_ReuseValues(t *testing.T) { - is := assert.New(t) - t.Run("reuse values should work with values", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) existingValues := map[string]any{ @@ -240,31 +241,33 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { rel.Config = existingValues err := upAction.cfg.Releases.Create(rel) - is.NoError(err) + req.NoError(err) upAction.ReuseValues = true // setting newValues and upgrading resi, err := upAction.Run(rel.Name, buildChart(), newValues) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) - is.NoError(err) + req.NoError(err) if updatedResi == nil { is.Fail("Updated Release is nil") return } updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) is.Equal(expectedValues, updatedRes.Config) }) t.Run("reuse values should not install disabled charts", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) chartDefaultValues := map[string]any{ "subchart": map[string]any{ @@ -301,7 +304,7 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { Version: 1, } err := upAction.cfg.Releases.Create(rel) - is.NoError(err) + req.NoError(err) upAction.ReuseValues = true sampleChartWithSubChart := buildChart( @@ -312,20 +315,20 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { ) // reusing values and upgrading resi, err := upAction.Run(rel.Name, sampleChartWithSubChart, map[string]any{}) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now get the upgraded release updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) - is.NoError(err) + req.NoError(err) if updatedResi == nil { is.Fail("Updated Release is nil") return } updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) is.Empty(updatedRes.Chart.Dependencies(), "expected 0 dependencies") @@ -340,9 +343,9 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { } func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { - is := assert.New(t) - t.Run("reset then reuse values should work with values", func(t *testing.T) { + is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) existingValues := map[string]any{ @@ -371,25 +374,25 @@ func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { rel.Config = existingValues err := upAction.cfg.Releases.Create(rel) - is.NoError(err) + req.NoError(err) upAction.ResetThenReuseValues = true // setting newValues and upgrading resi, err := upAction.Run(rel.Name, buildChart(withValues(newChartValues)), newValues) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) - is.NoError(err) + req.NoError(err) if updatedResi == nil { is.Fail("Updated Release is nil") return } updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) is.Equal(expectedValues, updatedRes.Config) @@ -440,9 +443,9 @@ func TestUpgradeRelease_Interrupted_Wait(t *testing.T) { req.Error(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Contains(res.Info.Description, "Upgrade \"interrupted-release\" failed: context canceled") - is.Equal(res.Info.Status, common.StatusFailed) + is.Equal(common.StatusFailed, res.Info.Status) } func TestUpgradeRelease_Interrupted_RollbackOnFailure(t *testing.T) { @@ -453,7 +456,7 @@ func TestUpgradeRelease_Interrupted_RollbackOnFailure(t *testing.T) { rel := releaseStub() rel.Name = "interrupted-release" rel.Info.Status = common.StatusDeployed - require.NoError(t, upAction.cfg.Releases.Create(rel)) + req.NoError(upAction.cfg.Releases.Create(rel)) failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient) failer.WaitDuration = 5 * time.Second @@ -469,14 +472,14 @@ func TestUpgradeRelease_Interrupted_RollbackOnFailure(t *testing.T) { req.Error(err) is.Contains(err.Error(), "release interrupted-release failed, and has been rolled back due to rollback-on-failure being set: context canceled") res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 3) - is.NoError(err) + req.NoError(err) updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) // Should have rolled back to the previous - is.Equal(updatedRes.Info.Status, common.StatusDeployed) + is.Equal(common.StatusDeployed, updatedRes.Info.Status) } func TestMergeCustomLabels(t *testing.T) { @@ -496,6 +499,7 @@ func TestMergeCustomLabels(t *testing.T) { func TestUpgradeRelease_Labels(t *testing.T) { is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) rel := releaseStub() @@ -508,7 +512,7 @@ func TestUpgradeRelease_Labels(t *testing.T) { rel.Info.Status = common.StatusDeployed err := upAction.cfg.Releases.Create(rel) - is.NoError(err) + req.NoError(err) upAction.Labels = map[string]string{ "key1": "null", @@ -517,39 +521,40 @@ func TestUpgradeRelease_Labels(t *testing.T) { } // setting newValues and upgrading resi, err := upAction.Run(rel.Name, buildChart(), nil) - is.NoError(err) + req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) // Now make sure it is actually upgraded and labels were merged updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) - is.NoError(err) + req.NoError(err) if updatedResi == nil { is.Fail("Updated Release is nil") return } updatedRes, err := releaserToV1Release(updatedResi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) is.Equal(mergeCustomLabels(rel.Labels, upAction.Labels), updatedRes.Labels) // Now make sure it is suppressed release still contains original labels initialResi, err := upAction.cfg.Releases.Get(res.Name, 1) - is.NoError(err) + req.NoError(err) if initialResi == nil { is.Fail("Updated Release is nil") return } initialRes, err := releaserToV1Release(initialResi) - is.NoError(err) - is.Equal(initialRes.Info.Status, common.StatusSuperseded) + req.NoError(err) + is.Equal(common.StatusSuperseded, initialRes.Info.Status) is.Equal(initialRes.Labels, rel.Labels) } func TestUpgradeRelease_SystemLabels(t *testing.T) { is := assert.New(t) + req := require.New(t) upAction := upgradeAction(t) rel := releaseStub() @@ -562,7 +567,7 @@ func TestUpgradeRelease_SystemLabels(t *testing.T) { rel.Info.Status = common.StatusDeployed err := upAction.cfg.Releases.Create(rel) - is.NoError(err) + req.NoError(err) upAction.Labels = map[string]string{ "key1": "null", @@ -596,7 +601,7 @@ func TestUpgradeRelease_DryRun(t *testing.T) { done() req.NoError(err) res, err := releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusPendingUpgrade, res.Info.Status) is.Contains(res.Manifest, "kind: Secret") @@ -604,7 +609,7 @@ func TestUpgradeRelease_DryRun(t *testing.T) { req.NoError(err) lastRelease, err := releaserToV1Release(lastReleasei) req.NoError(err) - is.Equal(lastRelease.Info.Status, common.StatusDeployed) + is.Equal(common.StatusDeployed, lastRelease.Info.Status) is.Equal(1, lastRelease.Version) // Test the case for hiding the secret to ensure it is not displayed @@ -616,7 +621,7 @@ func TestUpgradeRelease_DryRun(t *testing.T) { done() req.NoError(err) res, err = releaserToV1Release(resi) - is.NoError(err) + req.NoError(err) is.Equal(common.StatusPendingUpgrade, res.Info.Status) is.NotContains(res.Manifest, "kind: Secret") @@ -624,7 +629,7 @@ func TestUpgradeRelease_DryRun(t *testing.T) { req.NoError(err) lastRelease, err = releaserToV1Release(lastReleasei) req.NoError(err) - is.Equal(lastRelease.Info.Status, common.StatusDeployed) + is.Equal(common.StatusDeployed, lastRelease.Info.Status) is.Equal(1, lastRelease.Version) // Ensure in a dry run mode when using HideSecret @@ -715,7 +720,7 @@ func TestGetUpgradeServerSideValue(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { serverSideApply, err := getUpgradeServerSideValue(tt.actionServerSideOption, tt.releaseApplyMethod) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tt.expectedServerSideApply, serverSideApply) }) } diff --git a/pkg/action/validate_test.go b/pkg/action/validate_test.go index 3624d3676..75c29bf6b 100644 --- a/pkg/action/validate_test.go +++ b/pkg/action/validate_test.go @@ -25,6 +25,7 @@ import ( "helm.sh/helm/v4/pkg/kube" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/meta" @@ -130,7 +131,7 @@ func TestRequireAdoption(t *testing.T) { // Verify that a resource that lacks labels/annotations can be adopted found, err := requireAdoption(resources) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) @@ -155,7 +156,7 @@ func TestExistingResourceConflict(t *testing.T) { // Verify only existing resources are returned found, err := existingResourceConflict(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) @@ -171,21 +172,21 @@ func TestCheckOwnership(t *testing.T) { // Verify that a resource that lacks labels/annotations is not owned err := checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, err, `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set managed by label and verify annotation error message _ = accessor.SetLabels(deployFoo.Object, map[string]string{ appManagedByLabel: appManagedByHelm, }) err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set only the release name annotation and verify missing release namespace error message _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ helmReleaseNameAnnotation: "rel-a", }) err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set both release name and namespace annotations and verify no ownership errors _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ @@ -193,15 +194,15 @@ func TestCheckOwnership(t *testing.T) { helmReleaseNamespaceAnnotation: "ns-a", }) err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.NoError(t, err) + require.NoError(t, err) // Verify ownership error for wrong release name err = checkOwnership(deployFoo.Object, "rel-b", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) + require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) // Verify ownership error for wrong release namespace err = checkOwnership(deployFoo.Object, "rel-a", "ns-b") - assert.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) + require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) // Verify ownership error for wrong manager label _ = accessor.SetLabels(deployFoo.Object, map[string]string{ @@ -235,7 +236,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{owned1, owned2} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, ownedList, 2) assert.Empty(t, unownedList) }) @@ -247,7 +248,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{owned, unowned} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, ownedList, 1) assert.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) @@ -260,7 +261,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{missing} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Empty(t, ownedList) assert.Empty(t, unownedList) }) @@ -271,7 +272,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{noMeta} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Empty(t, ownedList) assert.Len(t, unownedList, 1) }) @@ -282,7 +283,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{otherRelease} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Empty(t, ownedList) assert.Len(t, unownedList, 1) }) @@ -295,7 +296,7 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { resources := kube.ResourceList{owned, unowned, missing} ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, ownedList, 1) assert.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) @@ -313,24 +314,24 @@ func TestSetMetadataVisitor(t *testing.T) { // Set release tracking metadata and verify no error err = resources.Visit(setMetadataVisitor("rel-a", "ns-a", true)) - assert.NoError(t, err) + require.NoError(t, err) // Verify that release "b" cannot take ownership of "a" err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - assert.Error(t, err) + require.Error(t, err) // Force release "b" to take ownership err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", true)) - assert.NoError(t, err) + require.NoError(t, err) // Check that there is now no ownership error when setting metadata without force err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - assert.NoError(t, err) + require.NoError(t, err) // Add a new resource that is missing ownership metadata and verify error resources.Append(newDeploymentResource("baz", "default", "")) err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), `Deployment "baz" in namespace "" cannot be owned`) } @@ -368,10 +369,10 @@ func TestValidateNameAndGenerateName(t *testing.T) { skip, err := validateNameAndGenerateName(tc.info) if tc.wantErr { - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), tc.errContains) } else { - assert.NoError(t, err) + require.NoError(t, err) } assert.Equal(t, tc.wantSkip, skip) diff --git a/pkg/chart/common/util/coalesce_test.go b/pkg/chart/common/util/coalesce_test.go index 33274920c..d7f46a1da 100644 --- a/pkg/chart/common/util/coalesce_test.go +++ b/pkg/chart/common/util/coalesce_test.go @@ -25,6 +25,7 @@ import ( "text/template" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -734,6 +735,7 @@ func TestConcatPrefix(t *testing.T) { // from issue #31643 where chart has data: {} and user provides data: {foo: bar, baz: ~} func TestCoalesceValuesEmptyMapWithNils(t *testing.T) { is := assert.New(t) + req := require.New(t) c := &chart.Chart{ Metadata: &chart.Metadata{Name: "test"}, @@ -750,7 +752,7 @@ func TestCoalesceValuesEmptyMapWithNils(t *testing.T) { } v, err := CoalesceValues(c, vals) - is.NoError(err) + req.NoError(err) data, ok := v["data"].(map[string]any) is.True(ok, "data is not a map") @@ -769,6 +771,7 @@ func TestCoalesceValuesEmptyMapWithNils(t *testing.T) { // Regression test for issue #31919. func TestCoalesceValuesSubchartDefaultNilsCleaned(t *testing.T) { is := assert.New(t) + req := require.New(t) // Subchart has a default with nil values (e.g. keyMapping: {password: null}) subchart := &chart.Chart{ @@ -789,7 +792,7 @@ func TestCoalesceValuesSubchartDefaultNilsCleaned(t *testing.T) { vals := map[string]any{} v, err := CoalesceValues(parent, vals) - is.NoError(err) + req.NoError(err) childVals, ok := v["child"].(map[string]any) is.True(ok, "child values should be a map") @@ -807,6 +810,7 @@ func TestCoalesceValuesSubchartDefaultNilsCleaned(t *testing.T) { // Regression test for issue #31919. func TestCoalesceValuesUserNullErasesSubchartDefault(t *testing.T) { is := assert.New(t) + req := require.New(t) subchart := &chart.Chart{ Metadata: &chart.Metadata{Name: "child"}, @@ -828,7 +832,7 @@ func TestCoalesceValuesUserNullErasesSubchartDefault(t *testing.T) { } v, err := CoalesceValues(parent, vals) - is.NoError(err) + req.NoError(err) childVals, ok := v["child"].(map[string]any) is.True(ok, "child values should be a map") @@ -843,6 +847,7 @@ func TestCoalesceValuesUserNullErasesSubchartDefault(t *testing.T) { // Regression test for issue #31971. func TestCoalesceValuesSubchartNilDoesNotShadowGlobal(t *testing.T) { is := assert.New(t) + req := require.New(t) subchart := &chart.Chart{ Metadata: &chart.Metadata{Name: "child"}, @@ -868,7 +873,7 @@ func TestCoalesceValuesSubchartNilDoesNotShadowGlobal(t *testing.T) { } v, err := CoalesceValues(parent, vals) - is.NoError(err) + req.NoError(err) childVals, ok := v["child"].(map[string]any) is.True(ok, "child values should be a map") @@ -887,6 +892,7 @@ func TestCoalesceValuesSubchartNilDoesNotShadowGlobal(t *testing.T) { // the same map. Regression test for the coalesceTablesFullKey merge path. func TestCoalesceValuesSubchartNilCleanedWhenUserPartiallyOverrides(t *testing.T) { is := assert.New(t) + req := require.New(t) subchart := &chart.Chart{ Metadata: &chart.Metadata{Name: "child"}, @@ -913,7 +919,7 @@ func TestCoalesceValuesSubchartNilCleanedWhenUserPartiallyOverrides(t *testing.T } v, err := CoalesceValues(parent, vals) - is.NoError(err) + req.NoError(err) childVals, ok := v["child"].(map[string]any) is.True(ok, "child values should be a map") diff --git a/pkg/chart/v2/lint/lint_test.go b/pkg/chart/v2/lint/lint_test.go index 4256281e0..85960131b 100644 --- a/pkg/chart/v2/lint/lint_test.go +++ b/pkg/chart/v2/lint/lint_test.go @@ -22,6 +22,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/v2/lint/support" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -130,7 +131,7 @@ func TestBadCrdFile(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) - assert.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") + require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index 498f2d3ba..c601de49e 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -224,7 +224,7 @@ func TestReadFile(t *testing.T) { assert.Error(t, err) return } - assert.NoError(t, err) + require.NoError(t, err) if tt.expectedData != nil { assert.Equal(t, tt.expectedData, got) diff --git a/pkg/cmd/helpers_test.go b/pkg/cmd/helpers_test.go index 37ceb6a85..3db5f38ab 100644 --- a/pkg/cmd/helpers_test.go +++ b/pkg/cmd/helpers_test.go @@ -286,9 +286,9 @@ func TestCmdGetDryRunFlagStrategy(t *testing.T) { t.Run(name, func(t *testing.T) { dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, tc.IsTemplate) if tc.ExpectedError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tc.ExpectedStrategy, dryRunStrategy) } diff --git a/pkg/cmd/history_test.go b/pkg/cmd/history_test.go index 3ec59a99f..b602168cb 100644 --- a/pkg/cmd/history_test.go +++ b/pkg/cmd/history_test.go @@ -451,7 +451,7 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { // Zero time value should be omitted assert.NotContains(t, result, "updated") - assert.Equal(t, float64(1), result["revision"]) + assert.InDelta(t, float64(1), result["revision"], 0.0001) assert.Equal(t, "deployed", result["status"]) assert.Equal(t, "mychart-1.0.0", result["chart"]) } diff --git a/pkg/downloader/cache_test.go b/pkg/downloader/cache_test.go index 7d7fb3059..d8a2c3768 100644 --- a/pkg/downloader/cache_test.go +++ b/pkg/downloader/cache_test.go @@ -94,7 +94,7 @@ func TestDiskCache_PutAndGet(t *testing.T) { // Get should return ErrNotExist for empty files _, err = cache.Get(emptyKey, CacheChart) - assert.ErrorIs(t, err, os.ErrNotExist, "Get for an empty file should return os.ErrNotExist") + require.ErrorIs(t, err, os.ErrNotExist, "Get for an empty file should return os.ErrNotExist") // But the file should exist _, err = os.Stat(path) diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index aea64a0b5..4924b6721 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -26,6 +26,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -679,7 +680,7 @@ func TestDedupeRepos(t *testing.T) { func TestWriteLock(t *testing.T) { fixedTime, err := time.Parse(time.RFC3339, "2025-07-04T00:00:00Z") - assert.NoError(t, err) + require.NoError(t, err) lock := &chart.Lock{ Generated: fixedTime, Digest: "sha256:12345", @@ -692,76 +693,76 @@ func TestWriteLock(t *testing.T) { }, } expectedContent, err := yaml.Marshal(lock) - assert.NoError(t, err) + require.NoError(t, err) t.Run("v2 lock file", func(t *testing.T) { dir := t.TempDir() err := writeLock(dir, lock, false) - assert.NoError(t, err) + require.NoError(t, err) lockfilePath := filepath.Join(dir, "Chart.lock") _, err = os.Stat(lockfilePath) - assert.NoError(t, err, "Chart.lock should exist") + require.NoError(t, err, "Chart.lock should exist") content, err := os.ReadFile(lockfilePath) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, expectedContent, content) // Check that requirements.lock does not exist _, err = os.Stat(filepath.Join(dir, "requirements.lock")) - assert.Error(t, err) + require.Error(t, err) assert.True(t, os.IsNotExist(err)) }) t.Run("v1 lock file", func(t *testing.T) { dir := t.TempDir() err := writeLock(dir, lock, true) - assert.NoError(t, err) + require.NoError(t, err) lockfilePath := filepath.Join(dir, "requirements.lock") _, err = os.Stat(lockfilePath) - assert.NoError(t, err, "requirements.lock should exist") + require.NoError(t, err, "requirements.lock should exist") content, err := os.ReadFile(lockfilePath) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, expectedContent, content) // Check that Chart.lock does not exist _, err = os.Stat(filepath.Join(dir, "Chart.lock")) - assert.Error(t, err) + require.Error(t, err) assert.True(t, os.IsNotExist(err)) }) t.Run("overwrite existing lock file", func(t *testing.T) { dir := t.TempDir() lockfilePath := filepath.Join(dir, "Chart.lock") - assert.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0o644)) + require.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0o644)) err = writeLock(dir, lock, false) - assert.NoError(t, err) + require.NoError(t, err) content, err := os.ReadFile(lockfilePath) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, expectedContent, content) }) t.Run("lock file is a symlink", func(t *testing.T) { dir := t.TempDir() dummyFile := filepath.Join(dir, "dummy.txt") - assert.NoError(t, os.WriteFile(dummyFile, []byte("dummy"), 0o644)) + require.NoError(t, os.WriteFile(dummyFile, []byte("dummy"), 0o644)) lockfilePath := filepath.Join(dir, "Chart.lock") - assert.NoError(t, os.Symlink(dummyFile, lockfilePath)) + require.NoError(t, os.Symlink(dummyFile, lockfilePath)) err = writeLock(dir, lock, false) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "the Chart.lock file is a symlink to") }) t.Run("chart path is not a directory", func(t *testing.T) { dir := t.TempDir() filePath := filepath.Join(dir, "not-a-dir") - assert.NoError(t, os.WriteFile(filePath, []byte("file"), 0o644)) + require.NoError(t, os.WriteFile(filePath, []byte("file"), 0o644)) err = writeLock(filePath, lock, false) assert.Error(t, err) diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index cf6a8d5c9..37f79478c 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -135,7 +135,7 @@ keyInElement1 = "valueInElement1"`, for _, tt := range tests { var b strings.Builder err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tt.expect, b.String(), tt.tpl) } @@ -187,7 +187,7 @@ keyInElement1 = "valueInElement1"`, var b strings.Builder err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) if tt.expect != nil { - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tt.expect, b.String(), tt.tpl) } else { assert.Error(t, err) @@ -475,7 +475,7 @@ func TestMerge(t *testing.T) { tpl := `{{merge .dst .src1 .src2}}` var b strings.Builder err := template.Must(template.New("test").Funcs(funcMap()).Parse(tpl)).Execute(&b, dict) - assert.NoError(t, err) + require.NoError(t, err) expected := map[string]any{ "a": "one", // key overridden diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 131695dc2..8a71e4b6b 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -968,7 +968,8 @@ func TestGetPodList(t *testing.T) { podList, err := c.GetPodList(namespace, metav1.ListOptions{}) clientAssertions := assert.New(t) - clientAssertions.NoError(err) + req := require.New(t) + req.NoError(err) podList.ResourceVersion = "" clientAssertions.Equal(&responsePodList, podList) } @@ -983,7 +984,8 @@ func TestOutputContainerLogsForPodList(t *testing.T) { outBufferFunc := func(_, _, _ string) io.Writer { return outBuffer } err := c.OutputContainerLogsForPodList(&somePodList, namespace, outBufferFunc) clientAssertions := assert.New(t) - clientAssertions.NoError(err) + req := require.New(t) + req.NoError(err) clientAssertions.Equal("fake logsfake logsfake logs", outBuffer.String()) } diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 73a424720..12c44b420 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -273,7 +273,7 @@ func getRuntimeObjFromManifests(t *testing.T, manifests []string) []runtime.Obje for _, manifest := range manifests { m := make(map[string]any) err := yaml.Unmarshal([]byte(manifest), &m) - assert.NoError(t, err) + require.NoError(t, err) resource := &unstructured.Unstructured{Object: m} objects = append(objects, resource) } @@ -285,7 +285,7 @@ func getResourceListFromRuntimeObjs(t *testing.T, c *Client, objs []runtime.Obje resourceList := ResourceList{} for _, obj := range objs { list, err := c.Build(objBody(obj), false) - assert.NoError(t, err) + require.NoError(t, err) resourceList = append(resourceList, list...) } return resourceList @@ -333,7 +333,7 @@ func TestStatusWaitForDelete(t *testing.T) { u := objToCreate.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } objsToDelete := getRuntimeObjFromManifests(t, tt.manifestsToDelete) for _, objToDelete := range objsToDelete { @@ -434,7 +434,7 @@ func TestStatusWait(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -491,7 +491,7 @@ func TestWaitForJobComplete(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) @@ -554,7 +554,7 @@ func TestWatchForReady(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) @@ -658,7 +658,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } if strings.Contains(tt.name, "delete") { @@ -840,7 +840,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } if strings.Contains(tt.name, "delet") { @@ -865,7 +865,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { } return } - assert.NoError(t, err) + require.NoError(t, err) assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } @@ -948,7 +948,7 @@ func TestStatusWaitMixedResources(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } if strings.Contains(tt.name, "delet") { @@ -973,7 +973,7 @@ func TestStatusWaitMixedResources(t *testing.T) { } return } - assert.NoError(t, err) + require.NoError(t, err) assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } @@ -1068,7 +1068,7 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -1140,7 +1140,7 @@ func TestStatusWaitWithJobsAndCustomReaders(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) @@ -1239,7 +1239,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := tt.testFunc(&sw, resourceList, time.Second*3) @@ -1788,7 +1788,7 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - assert.NoError(t, err) + require.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go index 73270b5a3..da730a22e 100644 --- a/pkg/kube/wait_test.go +++ b/pkg/kube/wait_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta2 "k8s.io/api/apps/v1beta2" @@ -227,10 +228,10 @@ func TestSelectorsForObject(t *testing.T) { t.Run(tt.name, func(t *testing.T) { selector, err := SelectorsForObject(tt.object.(runtime.Object)) if tt.expectError { - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), tt.errorContains) } else { - assert.NoError(t, err) + require.NoError(t, err) expected := labels.Set(tt.expectedLabels) assert.True(t, selector.Matches(expected), "expected selector to match") } diff --git a/pkg/postrenderer/postrenderer_test.go b/pkg/postrenderer/postrenderer_test.go index 824a1d179..cea6f9f76 100644 --- a/pkg/postrenderer/postrenderer_test.go +++ b/pkg/postrenderer/postrenderer_test.go @@ -50,15 +50,16 @@ func TestNewPostRenderPluginWithOneArgsRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) + req := require.New(t) s := cli.New() s.PluginsDirectory = "testdata/plugins" name := "postrenderer-v1" renderer, err := NewPostRendererPlugin(s, name, "ARG1") - require.NoError(t, err) + req.NoError(err) output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) - is.NoError(err) + req.NoError(err) is.Contains(output.String(), "ARG1") } @@ -68,14 +69,15 @@ func TestNewPostRenderPluginWithTwoArgsRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) + req := require.New(t) s := cli.New() s.PluginsDirectory = "testdata/plugins" name := "postrenderer-v1" renderer, err := NewPostRendererPlugin(s, name, "ARG1", "ARG2") - require.NoError(t, err) + req.NoError(err) output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) - is.NoError(err) + req.NoError(err) is.Contains(output.String(), "ARG1 ARG2") } diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index 23a32506d..e27c3d619 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -237,7 +237,7 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { // Verify value of created artifact in RFC3339 format _, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) - assert.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) + require.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) // Verify default creation time set result = generateOCIAnnotations(testChart, "") diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index f5f32ecb1..5f121f048 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -59,7 +59,7 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { }) lnCfg := net.ListenConfig{} listener, err := lnCfg.Listen(suite.T().Context(), "tcp", suite.AuthServerHost) - suite.NoError(err, "no error creating server listener") + suite.Require().NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -69,18 +69,18 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { // basic push, good ref testingChartCreationTime := "1977-09-02T22:04:05Z" chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") - suite.NoError(err, "no error loading test chart") + suite.Require().NoError(err, "no error loading test chart") meta, err := extractChartMeta(chartData) - suite.NoError(err, "no error extracting chart meta") + suite.Require().NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) - suite.Error(err, "error pushing good ref because auth server doesn't give proper token") + suite.Require().Error(err, "error pushing good ref because auth server doesn't give proper token") //check the url that authentication server received select { case urlStr := <-requestURL: u, err := url.Parse(urlStr) - suite.NoError(err, "no error parsing requested URL") + suite.Require().NoError(err, "no error parsing requested URL") suite.Equal("/auth", u.Path) suite.Equal("testservice", u.Query().Get("service")) @@ -105,7 +105,7 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { }) lnCfg := net.ListenConfig{} listener, err := lnCfg.Listen(suite.T().Context(), "tcp", suite.AuthServerHost) - suite.NoError(err, "no error creating server listener") + suite.Require().NoError(err, "no error creating server listener") ts := httptest.NewUnstartedServer(handler) ts.Listener = listener @@ -115,18 +115,18 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { // Load test chart (to build ref pushed in previous test) // Simple pull, chart only chartData, err := os.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz") - suite.NoError(err, "no error loading test chart") + suite.Require().NoError(err, "no error loading test chart") meta, err := extractChartMeta(chartData) - suite.NoError(err, "no error extracting chart meta") + suite.Require().NoError(err, "no error extracting chart meta") ref := fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version) _, err = suite.RegistryClient.Pull(ref) - suite.Error(err, "error pulling a simple chart because auth server doesn't give proper token") + suite.Require().Error(err, "error pulling a simple chart because auth server doesn't give proper token") //check the url that authentication server received select { case urlStr := <-requestURL: u, err := url.Parse(urlStr) - suite.NoError(err, "no error parsing requested URL") + suite.Require().NoError(err, "no error parsing requested URL") suite.Equal("/auth", u.Path) suite.Equal("testservice", u.Query().Get("service")) diff --git a/pkg/registry/reference_test.go b/pkg/registry/reference_test.go index f1a87fefc..07987cccb 100644 --- a/pkg/registry/reference_test.go +++ b/pkg/registry/reference_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func verify(t *testing.T, actual reference, registry, repository, tag, digest string) { @@ -45,30 +46,30 @@ func verify(t *testing.T, actual reference, registry, repository, tag, digest st func TestNewReference(t *testing.T) { actual, err := newReference("registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") actual, err = newReference("oci://registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") actual, err = newReference("a/b:1@c") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "a", "b", "1", "c") actual, err = newReference("a/b:@") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "a", "b", "", "") actual, err = newReference("registry.example.com/repository:1.0+001") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "registry.example.com", "repository", "1.0_001", "") actual, err = newReference("thing:1.0") - assert.Error(t, err) + require.Error(t, err) verify(t, actual, "", "", "", "") actual, err = newReference("registry.example.com/the/repository@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") - assert.NoError(t, err) + require.NoError(t, err) verify(t, actual, "registry.example.com", "the/repository", "", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888") } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index a1cf11310..afcf88db5 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -560,9 +560,9 @@ func testPull(suite *TestRegistry) { suite.Equal( "sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256", result.Prov.Digest) - suite.Equal("{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580\",\"size\":99},\"layers\":[{\"mediaType\":\"application/vnd.cncf.helm.chart.provenance.v1.prov\",\"digest\":\"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256\",\"size\":695},{\"mediaType\":\"application/vnd.cncf.helm.chart.content.v1.tar+gzip\",\"digest\":\"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\",\"size\":973}],\"annotations\":{\"org.opencontainers.image.created\":\"1977-09-02T22:04:05Z\",\"org.opencontainers.image.description\":\"A Helm chart for Kubernetes\",\"org.opencontainers.image.title\":\"signtest\",\"org.opencontainers.image.version\":\"0.1.0\"}}", + suite.JSONEq("{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580\",\"size\":99},\"layers\":[{\"mediaType\":\"application/vnd.cncf.helm.chart.provenance.v1.prov\",\"digest\":\"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256\",\"size\":695},{\"mediaType\":\"application/vnd.cncf.helm.chart.content.v1.tar+gzip\",\"digest\":\"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\",\"size\":973}],\"annotations\":{\"org.opencontainers.image.created\":\"1977-09-02T22:04:05Z\",\"org.opencontainers.image.description\":\"A Helm chart for Kubernetes\",\"org.opencontainers.image.title\":\"signtest\",\"org.opencontainers.image.version\":\"0.1.0\"}}", string(result.Manifest.Data)) - suite.Equal("{\"name\":\"signtest\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\",\"apiVersion\":\"v1\"}", + suite.JSONEq("{\"name\":\"signtest\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\",\"apiVersion\":\"v1\"}", string(result.Config.Data)) suite.Equal(chartData, result.Chart.Data) suite.Equal(provData, result.Prov.Data) diff --git a/pkg/release/common_test.go b/pkg/release/common_test.go index bc22971e9..1adfcd979 100644 --- a/pkg/release/common_test.go +++ b/pkg/release/common_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v2release "helm.sh/helm/v4/internal/release/v2" "helm.sh/helm/v4/pkg/release/common" @@ -31,6 +32,7 @@ func TestNewDefaultAccessor(t *testing.T) { // Testing the default implementation rather than NewAccessor which can be // overridden by developers. is := assert.New(t) + req := require.New(t) // Create release info := &rspb.Info{Status: common.StatusDeployed, LastDeployed: time.Now().Add(1000)} @@ -55,7 +57,7 @@ func TestNewDefaultAccessor(t *testing.T) { // can't be used with interfaces. The accessors enable access to the underlying data // in a manner that works with Go interfaces. accessor, err := newDefaultAccessor(rel) - is.NoError(err) + req.NoError(err) // Verify information is.Equal(rel.Name, accessor.Name()) @@ -68,6 +70,7 @@ func TestNewDefaultAccessor(t *testing.T) { func TestNewDefaultAccessorV2(t *testing.T) { // Testing the default implementation for v2 releases (charts/v3) is := assert.New(t) + req := require.New(t) // Create v2 release info := &v2release.Info{Status: common.StatusDeployed, LastDeployed: time.Now().Add(1000), Notes: "test notes"} @@ -93,7 +96,7 @@ func TestNewDefaultAccessorV2(t *testing.T) { // Test accessor creation accessor, err := newDefaultAccessor(rel) - is.NoError(err) + req.NoError(err) // Verify all accessor methods return correct values is.Equal(rel.Name, accessor.Name()) @@ -112,7 +115,7 @@ func TestNewDefaultAccessorV2(t *testing.T) { // Test hook accessor hookAccessor, err := newDefaultHookAccessor(hooks[0]) - is.NoError(err) + req.NoError(err) is.Equal("templates/hook.yaml", hookAccessor.Path()) is.Equal("hook manifest", hookAccessor.Manifest()) } @@ -120,6 +123,7 @@ func TestNewDefaultAccessorV2(t *testing.T) { func TestNewDefaultAccessorV2ByValue(t *testing.T) { // Test that passing v2 release by value also works is := assert.New(t) + req := require.New(t) info := &v2release.Info{Status: common.StatusDeployed, LastDeployed: time.Now()} rel := v2release.Release{ @@ -130,6 +134,6 @@ func TestNewDefaultAccessorV2ByValue(t *testing.T) { } accessor, err := newDefaultAccessor(rel) - is.NoError(err) + req.NoError(err) is.Equal("test-release", accessor.Name()) } diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 95f85faa6..f821e30d4 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -21,7 +21,7 @@ import ( "reflect" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" "helm.sh/helm/v4/pkg/release/common" @@ -296,7 +296,7 @@ func TestMemoryDelete(t *testing.T) { t.Errorf("expected end to be %d instead of %d", startLen-2, endLen) for _, ee := range end { rac, err := release.NewAccessor(ee) - assert.NoError(t, err, "unable to get release accessor") + require.NoError(t, err, "unable to get release accessor") t.Logf("Name: %s, Version: %d", rac.Name(), rac.Version()) } } diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 9b4203224..ec57ae311 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -24,7 +24,7 @@ import ( "reflect" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" "helm.sh/helm/v4/pkg/release/common" @@ -113,7 +113,7 @@ func TestStorageDelete(t *testing.T) { } rhist, err := releaseListToV1List(hist) - assert.NoError(t, err) + require.NoError(t, err) // We have now deleted one of the two records. if len(rhist) != 1 { @@ -204,7 +204,7 @@ func TestStorageDeployed(t *testing.T) { } rel, err := releaserToV1Release(rls) - assert.NoError(t, err) + require.NoError(t, err) switch { case rls == nil: @@ -247,7 +247,7 @@ func TestStorageDeployedWithCorruption(t *testing.T) { } rel, err := releaserToV1Release(rls) - assert.NoError(t, err) + require.NoError(t, err) switch { case rls == nil: @@ -387,12 +387,10 @@ func TestStorageRemoveLeastRecent(t *testing.T) { // On inserting the 5th record, we expect two records to be pruned from history. hist, err := storage.History(name) - assert.NoError(t, err) + require.NoError(t, err) rhist, err := releaseListToV1List(hist) - assert.NoError(t, err) - if err != nil { - t.Fatal(err) - } else if len(rhist) != storage.MaxHistory { + require.NoError(t, err) + if len(rhist) != storage.MaxHistory { for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } @@ -440,7 +438,7 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { t.Fatal(err) } else if len(hist) != storage.MaxHistory { rhist, err := releaseListToV1List(hist) - assert.NoError(t, err) + require.NoError(t, err) for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } @@ -454,7 +452,7 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { } rhist, err := releaseListToV1List(hist) - assert.NoError(t, err) + require.NoError(t, err) for _, item := range rhist { if !expectedVersions[item.Version] { t.Errorf("Release version %d, found when not expected", item.Version) @@ -490,7 +488,7 @@ func TestStorageLast(t *testing.T) { } rel, err := releaserToV1Release(h) - assert.NoError(t, err) + require.NoError(t, err) if rel.Version != 4 { t.Errorf("Expected revision 4, got %d", rel.Version) @@ -544,7 +542,7 @@ func TestUpgradeInitiallyFailedReleaseWithHistoryLimit(t *testing.T) { } rhist, err := releaseListToV1List(hist) - assert.NoError(t, err) + require.NoError(t, err) for i, rel := range rhist { wantVersion := i + 2 if rel.Version != wantVersion { From 4ade4a5495b81a4cf465906a2414267ed0b1dcc8 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 09:19:55 +0000 Subject: [PATCH 040/161] test: replace assert.Contains with assert.ErrorContains for better error handling Signed-off-by: Matthieu MOREL --- internal/chart/v3/lint/rules/values_test.go | 8 +--- internal/plugin/config_test.go | 3 +- internal/plugin/loader_test.go | 6 +-- internal/plugin/metadata_v1_test.go | 4 +- pkg/action/action_test.go | 22 ++++------- pkg/action/get_metadata_test.go | 6 +-- pkg/action/get_values_test.go | 6 +-- pkg/action/install_test.go | 5 +-- pkg/action/release_testing_test.go | 3 +- pkg/action/validate_test.go | 6 +-- pkg/chart/v2/lint/rules/values_test.go | 8 +--- pkg/cli/values/options_test.go | 3 +- pkg/downloader/manager_test.go | 3 +- pkg/kube/client_test.go | 25 +++++------- pkg/kube/statuswait_test.go | 44 +++++++++------------ pkg/kube/wait_test.go | 3 +- pkg/registry/tag_test.go | 10 ++--- 17 files changed, 59 insertions(+), 106 deletions(-) diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index c0d2f5299..36f5c403e 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -92,11 +92,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { valfile := filepath.Join(tmpdir, "values.yaml") err := validateValuesFile(valfile, map[string]any{}, false) - if err == nil { - t.Fatal("expected values file to fail parsing") - } - - assert.Contains(t, err.Error(), "- at '/username': got number, want string") + assert.ErrorContains(t, err, "- at '/username': got number, want string") } func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { @@ -167,7 +163,7 @@ func TestValidateValuesFile(t *testing.T) { case err == nil && tt.errorMessage != "": t.Error("expected values file to fail parsing") case err != nil && tt.errorMessage != "": - assert.Contains(t, err.Error(), tt.errorMessage, "Failed with unexpected error") + assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") } }) } diff --git a/internal/plugin/config_test.go b/internal/plugin/config_test.go index beac05abf..ec81ffed6 100644 --- a/internal/plugin/config_test.go +++ b/internal/plugin/config_test.go @@ -49,8 +49,7 @@ func TestUnmarshaConfig(t *testing.T) { config, err := unmarshalConfig("cli/v1", map[string]any{ "invalid field": "foo", }) - require.Error(t, err) - assert.Contains(t, err.Error(), "field not found") + require.ErrorContains(t, err, "field not found") assert.Nil(t, config) } } diff --git a/internal/plugin/loader_test.go b/internal/plugin/loader_test.go index cb0de968d..4b98a6f83 100644 --- a/internal/plugin/loader_test.go +++ b/internal/plugin/loader_test.go @@ -295,8 +295,7 @@ command: echo test`, m, err := loadMetadataLegacy([]byte(tc.yaml)) if tc.expectError { - require.Error(t, err) - assert.Contains(t, err.Error(), tc.errorContains) + require.ErrorContains(t, err, tc.errorContains) t.Logf("Legacy error (validation catches empty name): %v", err) if tc.logNote != "" { t.Log(tc.logNote) @@ -342,8 +341,7 @@ runtime: subprocess m, err := loadMetadataV1([]byte(tc.yaml)) if tc.expectError { - require.Error(t, err) - assert.Contains(t, err.Error(), tc.errorContains) + require.ErrorContains(t, err, tc.errorContains) t.Logf("V1 error (strict unmarshalling): %v", err) } else { require.NoError(t, err) diff --git a/internal/plugin/metadata_v1_test.go b/internal/plugin/metadata_v1_test.go index 21a78549e..74c67178e 100644 --- a/internal/plugin/metadata_v1_test.go +++ b/internal/plugin/metadata_v1_test.go @@ -19,7 +19,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMetadataV1ValidateVersion(t *testing.T) { @@ -79,8 +78,7 @@ func TestMetadataV1ValidateVersion(t *testing.T) { m := base() m.Version = tc.version err := m.Validate() - require.Error(t, err) - assert.Contains(t, err.Error(), tc.errMsg) + assert.ErrorContains(t, err, tc.errMsg) }) } } diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 045fa7d1e..4ad08b761 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -358,8 +358,7 @@ func TestConfiguration_Init(t *testing.T) { actualErr := cfg.Init(nil, "default", tt.helmDriver) if tt.expectErr { - require.Error(t, actualErr) - assert.Contains(t, actualErr.Error(), tt.errMsg) + require.ErrorContains(t, actualErr, tt.errMsg) } else { require.NoError(t, actualErr) assert.IsType(t, tt.expectedDriverType, cfg.Releases.Driver) @@ -1575,8 +1574,7 @@ data: merged, err := annotateAndMerge(tt.files) if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) + assert.ErrorContains(t, err, tt.expectedError) } else { require.NoError(t, err) assert.NotNil(t, merged) @@ -1738,8 +1736,7 @@ data: files, err := splitAndDeannotate(tt.input, "test") if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) + require.ErrorContains(t, err, tt.expectedError) } else { require.NoError(t, err) assert.Len(t, files, len(tt.expectedFiles)) @@ -1874,8 +1871,7 @@ func TestRenderResources_PostRenderer_Error(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - require.Error(t, err) - assert.Contains(t, err.Error(), "error while running post render on files") + assert.ErrorContains(t, err, "error while running post render on files") } func TestRenderResources_PostRenderer_MergeError(t *testing.T) { @@ -1903,7 +1899,7 @@ func TestRenderResources_PostRenderer_MergeError(t *testing.T) { ) require.Error(t, err) - assert.Contains(t, err.Error(), "error merging manifests") + assert.ErrorContains(t, err, "error merging manifests") } func TestRenderResources_PostRenderer_SplitError(t *testing.T) { @@ -1924,8 +1920,7 @@ func TestRenderResources_PostRenderer_SplitError(t *testing.T) { mockPR, false, false, false, PostRenderStrategyCombined, ) - require.Error(t, err) - assert.Contains(t, err.Error(), "error while parsing post rendered output: error parsing YAML: MalformedYAMLError:") + assert.ErrorContains(t, err, "error while parsing post rendered output: error parsing YAML: MalformedYAMLError:") } func TestRenderResources_PostRenderer_Integration(t *testing.T) { @@ -2284,9 +2279,8 @@ metadata: mockPR, false, false, false, PostRenderStrategy("bogus"), ) - require.Error(t, err) - assert.Contains(t, err.Error(), "unknown post-render strategy") - assert.Contains(t, err.Error(), "bogus") + require.ErrorContains(t, err, "unknown post-render strategy") + assert.ErrorContains(t, err, "bogus") } func TestDetermineReleaseSSAApplyMethod(t *testing.T) { diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index ee0bd84a0..37f20fb60 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -443,8 +443,7 @@ func TestGetMetadata_Run_UnreachableKubeClient(t *testing.T) { client := NewGetMetadata(cfg) _, err := client.Run("test-release") - require.Error(t, err) - assert.Contains(t, err.Error(), "connection refused") + assert.ErrorContains(t, err, "connection refused") } func TestGetMetadata_Run_ReleaseNotFound(t *testing.T) { @@ -452,8 +451,7 @@ func TestGetMetadata_Run_ReleaseNotFound(t *testing.T) { client := NewGetMetadata(cfg) _, err := client.Run("non-existent-release") - require.Error(t, err) - assert.Contains(t, err.Error(), "not found") + assert.ErrorContains(t, err, "not found") } func TestGetMetadata_Run_EmptyAppVersion(t *testing.T) { diff --git a/pkg/action/get_values_test.go b/pkg/action/get_values_test.go index ce937b234..7e455baee 100644 --- a/pkg/action/get_values_test.go +++ b/pkg/action/get_values_test.go @@ -177,8 +177,7 @@ func TestGetValues_Run_UnreachableKubeClient(t *testing.T) { client := NewGetValues(cfg) _, err := client.Run("test-release") - require.Error(t, err) - assert.Contains(t, err.Error(), "connection refused") + assert.ErrorContains(t, err, "connection refused") } func TestGetValues_Run_ReleaseNotFound(t *testing.T) { @@ -186,8 +185,7 @@ func TestGetValues_Run_ReleaseNotFound(t *testing.T) { client := NewGetValues(cfg) _, err := client.Run("non-existent-release") - require.Error(t, err) - assert.Contains(t, err.Error(), "not found") + assert.ErrorContains(t, err, "not found") } func TestGetValues_Run_NilConfig(t *testing.T) { diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 28f989524..0d0e58e4a 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -334,10 +334,7 @@ func TestInstallRelease_NoName(t *testing.T) { instAction.ReleaseName = "" vals := map[string]any{} _, err := instAction.Run(buildChart(), vals) - if err == nil { - t.Fatal("expected failure when no name is specified") - } - assert.Contains(t, err.Error(), "no name provided") + assert.ErrorContains(t, err, "no name provided") } func TestInstallRelease_WithNotes(t *testing.T) { diff --git a/pkg/action/release_testing_test.go b/pkg/action/release_testing_test.go index d2a365cba..48a3251a1 100644 --- a/pkg/action/release_testing_test.go +++ b/pkg/action/release_testing_test.go @@ -231,8 +231,7 @@ func TestGetContainerLogs_PodNotFound(t *testing.T) { var buf bytes.Buffer err := rt.getContainerLogs(&buf, client, "nonexistent-pod") - require.Error(t, err) - assert.Contains(t, err.Error(), "unable to get pod nonexistent-pod") + assert.ErrorContains(t, err, "unable to get pod nonexistent-pod") } func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) { diff --git a/pkg/action/validate_test.go b/pkg/action/validate_test.go index 75c29bf6b..878bec599 100644 --- a/pkg/action/validate_test.go +++ b/pkg/action/validate_test.go @@ -331,8 +331,7 @@ func TestSetMetadataVisitor(t *testing.T) { // Add a new resource that is missing ownership metadata and verify error resources.Append(newDeploymentResource("baz", "default", "")) err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - require.Error(t, err) - assert.Contains(t, err.Error(), `Deployment "baz" in namespace "" cannot be owned`) + assert.ErrorContains(t, err, `Deployment "baz" in namespace "" cannot be owned`) } func TestValidateNameAndGenerateName(t *testing.T) { @@ -369,8 +368,7 @@ func TestValidateNameAndGenerateName(t *testing.T) { skip, err := validateNameAndGenerateName(tc.info) if tc.wantErr { - require.Error(t, err) - assert.Contains(t, err.Error(), tc.errContains) + require.ErrorContains(t, err, tc.errContains) } else { require.NoError(t, err) } diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index c0d2f5299..36f5c403e 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -92,11 +92,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { valfile := filepath.Join(tmpdir, "values.yaml") err := validateValuesFile(valfile, map[string]any{}, false) - if err == nil { - t.Fatal("expected values file to fail parsing") - } - - assert.Contains(t, err.Error(), "- at '/username': got number, want string") + assert.ErrorContains(t, err, "- at '/username': got number, want string") } func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { @@ -167,7 +163,7 @@ func TestValidateValuesFile(t *testing.T) { case err == nil && tt.errorMessage != "": t.Error("expected values file to fail parsing") case err != nil && tt.errorMessage != "": - assert.Contains(t, err.Error(), tt.errorMessage, "Failed with unexpected error") + assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") } }) } diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index c601de49e..40590f33f 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -258,8 +258,7 @@ func TestReadFileErrorMessages(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := readFile(tt.filePath, tt.providers) - require.Error(t, err) - assert.Contains(t, err.Error(), tt.wantErr) + require.ErrorContains(t, err, tt.wantErr) }) } } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 4924b6721..e0cea0cd2 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -755,8 +755,7 @@ func TestWriteLock(t *testing.T) { require.NoError(t, os.Symlink(dummyFile, lockfilePath)) err = writeLock(dir, lock, false) - require.Error(t, err) - assert.Contains(t, err.Error(), "the Chart.lock file is a symlink to") + assert.ErrorContains(t, err, "the Chart.lock file is a symlink to") }) t.Run("chart path is not a directory", func(t *testing.T) { diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 8a71e4b6b..4a28fc5ed 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -539,8 +539,7 @@ func TestUpdate(t *testing.T) { ClientUpdateOptionUpgradeClientSideFieldManager(true)) if tc.ExpectedError != "" { - require.Error(t, err) - require.Contains(t, err.Error(), tc.ExpectedError) + require.ErrorContains(t, err, tc.ExpectedError) } else { require.NoError(t, err) } @@ -558,7 +557,7 @@ func TestUpdate(t *testing.T) { if tc.ExpectedError != "" { require.Error(t, err) - require.Contains(t, err.Error(), tc.ExpectedError) + require.ErrorContains(t, err, tc.ExpectedError) } else { require.NoError(t, err) } @@ -1939,7 +1938,7 @@ func TestClientWaitContextCancellationLegacy(t *testing.T) { err = c.Wait(resources, time.Second*30) require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { @@ -1993,8 +1992,7 @@ func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) err = c.WaitWithJobs(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { @@ -2058,8 +2056,7 @@ func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { } err = c.WaitForDelete(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitContextNilDoesNotPanic(t *testing.T) { @@ -2166,8 +2163,7 @@ func TestClientWaitContextPreCancelledLegacy(t *testing.T) { assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) err = c.Wait(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitContextCancellationStatusWatcher(t *testing.T) { @@ -2193,8 +2189,7 @@ metadata: cancel() err = c.Wait(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitWithJobsContextCancellationStatusWatcher(t *testing.T) { @@ -2220,8 +2215,7 @@ metadata: cancel() err = c.WaitWithJobs(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } func TestClientWaitForDeleteContextCancellationStatusWatcher(t *testing.T) { @@ -2252,8 +2246,7 @@ status: cancel() err = c.WaitForDelete(resources, time.Second*30) - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) } // testStatusReader is a custom status reader for testing that returns a configurable status. diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 12c44b420..14f10124c 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -350,7 +350,7 @@ func TestStatusWaitForDelete(t *testing.T) { if tt.expectErrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -441,7 +441,7 @@ func TestStatusWait(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -498,7 +498,7 @@ func TestWaitForJobComplete(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -561,7 +561,7 @@ func TestWatchForReady(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -679,7 +679,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -861,7 +861,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { if tt.expectErrs != nil { require.Error(t, err) for _, expectedErr := range tt.expectErrs { - assert.Contains(t, err.Error(), expectedErr.Error()) + require.ErrorContains(t, err, expectedErr.Error()) } return } @@ -969,7 +969,7 @@ func TestStatusWaitMixedResources(t *testing.T) { if tt.expectErrs != nil { require.Error(t, err) for _, expectedErr := range tt.expectErrs { - assert.Contains(t, err.Error(), expectedErr.Error()) + require.ErrorContains(t, err, expectedErr.Error()) } return } @@ -1075,7 +1075,7 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -1246,7 +1246,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } @@ -1328,8 +1328,7 @@ func TestMethodSpecificContextCancellation(t *testing.T) { err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled method context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("Wait uses method-specific context", func(t *testing.T) { @@ -1362,8 +1361,7 @@ func TestMethodSpecificContextCancellation(t *testing.T) { err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled method context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("WaitWithJobs uses method-specific context", func(t *testing.T) { @@ -1396,8 +1394,7 @@ func TestMethodSpecificContextCancellation(t *testing.T) { err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled method context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("WaitForDelete uses method-specific context", func(t *testing.T) { @@ -1430,8 +1427,7 @@ func TestMethodSpecificContextCancellation(t *testing.T) { err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled method context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) } @@ -1468,8 +1464,7 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled general context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("Wait falls back to general context when method context is nil", func(t *testing.T) { @@ -1502,8 +1497,7 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled general context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("WaitWithJobs falls back to general context when method context is nil", func(t *testing.T) { @@ -1536,8 +1530,7 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled general context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) t.Run("WaitForDelete falls back to general context when method context is nil", func(t *testing.T) { @@ -1570,8 +1563,7 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled general context - require.Error(t, err) - assert.Contains(t, err.Error(), "context canceled") + assert.ErrorContains(t, err, "context canceled") }) } @@ -1795,7 +1787,7 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { - assert.Contains(t, err.Error(), expectedErrStr) + require.ErrorContains(t, err, expectedErrStr) } return } diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go index da730a22e..acdfffa23 100644 --- a/pkg/kube/wait_test.go +++ b/pkg/kube/wait_test.go @@ -228,8 +228,7 @@ func TestSelectorsForObject(t *testing.T) { t.Run(tt.name, func(t *testing.T) { selector, err := SelectorsForObject(tt.object.(runtime.Object)) if tt.expectError { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.errorContains) + require.ErrorContains(t, err, tt.errorContains) } else { require.NoError(t, err) expected := labels.Set(tt.expectedLabels) diff --git a/pkg/registry/tag_test.go b/pkg/registry/tag_test.go index 830eac7e1..e6f447eb3 100644 --- a/pkg/registry/tag_test.go +++ b/pkg/registry/tag_test.go @@ -19,6 +19,7 @@ package registry import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -61,15 +62,14 @@ func TestGetTagMatchingVersionOrConstraint_InvalidConstraint(t *testing.T) { func TestGetTagMatchingVersionOrConstraint_NoMatches(t *testing.T) { tags := []string{"0.1.0", "0.2.0"} _, err := GetTagMatchingVersionOrConstraint(tags, ">=1.0.0") - require.Error(t, err, "expected error when no tags match") - require.Contains(t, err.Error(), ">=1.0.0", "expected error to contain version string") + assert.ErrorContains(t, err, ">=1.0.0", "expected error to contain version string") } func TestGetTagMatchingVersionOrConstraint_SkipsNonSemverTags(t *testing.T) { tags := []string{"alpha", "1.0.0", "beta", "1.1.0"} got, err := GetTagMatchingVersionOrConstraint(tags, ">=1.0.0 <2.0.0") require.NoError(t, err) - require.Equal(t, "1.0.0", got) + assert.Equal(t, "1.0.0", got) } func TestGetTagMatchingVersionOrConstraint_OrderMatters_FirstMatchReturned(t *testing.T) { @@ -77,7 +77,7 @@ func TestGetTagMatchingVersionOrConstraint_OrderMatters_FirstMatchReturned(t *te tags := []string{"1.3.0", "1.2.0"} got, err := GetTagMatchingVersionOrConstraint(tags, ">=1.2.0 <2.0.0") require.NoError(t, err) - require.Equal(t, "1.3.0", got, "first satisfying tag") + assert.Equal(t, "1.3.0", got, "first satisfying tag") } func TestGetTagMatchingVersionOrConstraint_ExactMatchHasPrecedence(t *testing.T) { @@ -85,5 +85,5 @@ func TestGetTagMatchingVersionOrConstraint_ExactMatchHasPrecedence(t *testing.T) tags := []string{"1.3.0", "1.2.3"} got, err := GetTagMatchingVersionOrConstraint(tags, "1.2.3") require.NoError(t, err) - require.Equal(t, "1.2.3", got, "expected exact match") + assert.Equal(t, "1.2.3", got, "expected exact match") } From 65077c10fa3e4f339142f498d84c1c7bfb1d320b Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 09:37:12 +0000 Subject: [PATCH 041/161] test: replace assert.Equal with require.EqualError for improved error handling Signed-off-by: Matthieu MOREL --- pkg/strvals/literal_parser_test.go | 8 ++------ pkg/strvals/parser_test.go | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index 5d65557c5..aab8e1b73 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -451,9 +451,7 @@ func TestParseLiteralNestedLevels(t *testing.T) { if err != nil { if tt.err { if tt.errStr != "" { - if err.Error() != tt.errStr { - assert.Equal(t, tt.errStr, err.Error()) - } + require.EqualError(t, err, tt.errStr) } continue } @@ -468,9 +466,7 @@ func TestParseLiteralNestedLevels(t *testing.T) { require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 6d254ca8d..1b73ae16a 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -779,9 +779,7 @@ func TestParseSetNestedLevels(t *testing.T) { if err != nil { if tt.err { if tt.errStr != "" { - if err.Error() != tt.errStr { - assert.Equal(t, tt.errStr, err.Error()) - } + require.EqualError(t, err, tt.errStr) } continue } @@ -794,9 +792,7 @@ func TestParseSetNestedLevels(t *testing.T) { y1, err := yaml.Marshal(tt.expect) require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") if !bytes.Equal(y1, y2) { assert.Equal(t, string(y1), string(y2), tt.str) From c1569ea83ff40ab534f3db531316cb0408717d3c Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 17:27:08 +0200 Subject: [PATCH 042/161] Update pkg/cmd/history_test.go Co-authored-by: George Jenkins Signed-off-by: Matthieu MOREL --- pkg/cmd/history_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/history_test.go b/pkg/cmd/history_test.go index b602168cb..2bace98e0 100644 --- a/pkg/cmd/history_test.go +++ b/pkg/cmd/history_test.go @@ -451,7 +451,7 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { // Zero time value should be omitted assert.NotContains(t, result, "updated") - assert.InDelta(t, float64(1), result["revision"], 0.0001) + assert.InDelta(t, float64(1), result["revision"], 0.0) assert.Equal(t, "deployed", result["status"]) assert.Equal(t, "mychart-1.0.0", result["chart"]) } From 96b315f188932b7602e1ab1497e2d81d1caa8068 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 6 Jul 2026 23:16:46 +0200 Subject: [PATCH 043/161] chore: fix emptyStringTest, nestingReduce and singleCaseSwitch checks issues from gocritic Signed-off-by: Matthieu MOREL --- .golangci.yml | 3 - internal/chart/v3/lint/rules/chartfile.go | 2 +- internal/chart/v3/util/dependencies.go | 2 +- .../plugin/installer/http_installer_test.go | 2 +- internal/plugin/metadata.go | 2 +- internal/plugin/metadata_legacy.go | 2 +- internal/plugin/subprocess_commands.go | 4 +- .../release/v2/util/manifest_sorter_test.go | 37 ++++---- pkg/action/install.go | 2 +- pkg/action/show_test.go | 2 +- pkg/action/uninstall.go | 2 +- pkg/action/upgrade.go | 6 +- pkg/chart/v2/lint/rules/chartfile.go | 2 +- pkg/chart/v2/util/dependencies.go | 2 +- pkg/cli/values/options.go | 2 +- pkg/cmd/get_notes.go | 2 +- pkg/cmd/load_plugins.go | 4 +- pkg/cmd/package_test.go | 4 +- pkg/cmd/plugin_test.go | 2 +- pkg/cmd/repo_add.go | 2 +- pkg/cmd/root.go | 2 +- pkg/cmd/search_repo.go | 6 +- pkg/cmd/status.go | 2 +- pkg/downloader/chart_downloader.go | 2 +- pkg/downloader/chart_downloader_test.go | 2 +- pkg/downloader/manager.go | 88 ++++++++++--------- pkg/engine/engine.go | 2 +- pkg/kube/client.go | 2 +- pkg/kube/statuswait.go | 7 +- pkg/provenance/sign_test.go | 2 +- pkg/registry/chart.go | 8 +- pkg/registry/client.go | 3 +- pkg/registry/transport.go | 2 +- pkg/release/v1/util/manifest_sorter_test.go | 37 ++++---- pkg/repo/v1/index.go | 6 +- pkg/strvals/parser.go | 4 +- 36 files changed, 129 insertions(+), 132 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 518e47052..067b102d0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -91,18 +91,15 @@ linters: - commentFormatting - deferInLoop - elseif - - emptyStringTest - exposedSyncMutex - filepathJoin - hugeParam - ifElseChain - importShadow - - nestingReduce - nilValReturn - paramTypeCombine - ptrToRefParam - rangeValCopy - - singleCaseSwitch - todoCommentWithoutDetail - tooManyResultsChecker - uncheckedInlineErr diff --git a/internal/chart/v3/lint/rules/chartfile.go b/internal/chart/v3/lint/rules/chartfile.go index 29991a8d5..6f51a1de5 100644 --- a/internal/chart/v3/lint/rules/chartfile.go +++ b/internal/chart/v3/lint/rules/chartfile.go @@ -205,7 +205,7 @@ func validateChartDependencies(cf *chart.Metadata) error { } func validateChartType(cf *chart.Metadata) error { - if len(cf.Type) > 0 && cf.APIVersion != chart.APIVersionV3 { + if cf.Type != "" && cf.APIVersion != chart.APIVersionV3 { return fmt.Errorf("chart type is not valid in apiVersion '%s'. It is valid in apiVersion '%s'", cf.APIVersion, chart.APIVersionV3) } return nil diff --git a/internal/chart/v3/util/dependencies.go b/internal/chart/v3/util/dependencies.go index b31f7eb96..e1b3e0b97 100644 --- a/internal/chart/v3/util/dependencies.go +++ b/internal/chart/v3/util/dependencies.go @@ -43,7 +43,7 @@ func processDependencyConditions(reqs []*chart.Dependency, cvals common.Values, } for _, r := range reqs { for c := range strings.SplitSeq(strings.TrimSpace(r.Condition), ",") { - if len(c) > 0 { + if c != "" { // retrieve value vv, err := cvals.PathValue(cpath + c) var errNoValue common.ErrNoValue diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index b080aa2ef..cbd868f3a 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -342,7 +342,7 @@ func TestMediaTypeToExtension(t *testing.T) { if shouldPass && ext == "" { t.Error("Expected an extension but got empty string") } - if !shouldPass && len(ext) != 0 { + if !shouldPass && ext != "" { t.Error("Expected extension to be empty for unrecognized type") } } diff --git a/internal/plugin/metadata.go b/internal/plugin/metadata.go index 562861b1c..53d6da4e6 100644 --- a/internal/plugin/metadata.go +++ b/internal/plugin/metadata.go @@ -165,7 +165,7 @@ func buildLegacyRuntimeConfig(m MetadataLegacy) RuntimeConfig { } platformCommand := m.PlatformCommand - if len(platformCommand) == 0 && len(m.Command) > 0 { + if len(platformCommand) == 0 && m.Command != "" { platformCommand = []PlatformCommand{{Command: m.Command}} } diff --git a/internal/plugin/metadata_legacy.go b/internal/plugin/metadata_legacy.go index 26132a783..0bc11a81a 100644 --- a/internal/plugin/metadata_legacy.go +++ b/internal/plugin/metadata_legacy.go @@ -81,7 +81,7 @@ func (m *MetadataLegacy) Validate() error { m.Usage = sanitizeString(m.Usage) - if len(m.PlatformCommand) > 0 && len(m.Command) > 0 { + if len(m.PlatformCommand) > 0 && m.Command != "" { return errors.New("both platformCommand and command are set") } diff --git a/internal/plugin/subprocess_commands.go b/internal/plugin/subprocess_commands.go index 211ce5ebf..eb3e2b11b 100644 --- a/internal/plugin/subprocess_commands.go +++ b/internal/plugin/subprocess_commands.go @@ -48,12 +48,12 @@ func getPlatformCommand(cmds []PlatformCommand) ([]string, []string) { return strings.Split(c.Command, " "), c.Args } - if (len(c.OperatingSystem) > 0 && !eq(c.OperatingSystem, runtime.GOOS)) || len(c.Architecture) > 0 { + if (c.OperatingSystem != "" && !eq(c.OperatingSystem, runtime.GOOS)) || c.Architecture != "" { // Skip if OS is not empty and doesn't match or if arch is set as a set arch requires an OS match continue } - if !foundOs && len(c.OperatingSystem) > 0 && eq(c.OperatingSystem, runtime.GOOS) { + if !foundOs && c.OperatingSystem != "" && eq(c.OperatingSystem, runtime.GOOS) { // First OS match with empty arch, can only be overridden by a direct match command = strings.Split(c.Command, " ") args = c.Args diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index 1c932d70c..eac9c9f36 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -149,27 +149,28 @@ metadata: for _, out := range hs { found := false for _, expect := range data { - if out.Path == expect.path { - found = true - assert.Equal(t, expect.path, out.Path) - nameFound := false - for _, expectedName := range expect.name { - if out.Name == expectedName { - nameFound = true - } + if out.Path != expect.path { + continue + } + found = true + assert.Equal(t, expect.path, out.Path) + nameFound := false + for _, expectedName := range expect.name { + if out.Name == expectedName { + nameFound = true } - assert.True(t, nameFound, "Got unexpected name %s", out.Name) - kindFound := false - for _, expectedKind := range expect.kind { - if out.Kind == expectedKind { - kindFound = true - } + } + assert.True(t, nameFound, "Got unexpected name %s", out.Name) + kindFound := false + for _, expectedKind := range expect.kind { + if out.Kind == expectedKind { + kindFound = true } - assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) - - expectedHooks := expect.hooks[out.Name] - assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } + assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) + + expectedHooks := expect.hooks[out.Name] + assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } assert.True(t, found, "Result not found: %v", out) } diff --git a/pkg/action/install.go b/pkg/action/install.go index d36d2fc3e..d73eca619 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -558,7 +558,7 @@ func (i *Install) performInstall(rel *release.Release, toBeAdopted kube.Resource } } - if len(i.Description) > 0 { + if i.Description != "" { rel.SetStatus(rcommon.StatusDeployed, i.Description) } else { rel.SetStatus(rcommon.StatusDeployed, "Install complete") diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 854dee07a..0dde7fb74 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -86,7 +86,7 @@ func TestShowNoValues(t *testing.T) { t.Fatal(err) } - if len(output) != 0 { + if output != "" { t.Errorf("expected empty values buffer, got %s", output) } } diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index b14305112..47b2e47de 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -234,7 +234,7 @@ func (u *Uninstall) Run(name string) (*releasei.UninstallReleaseResponse, error) } rel.Info.Status = common.StatusUninstalled - if len(u.Description) > 0 { + if u.Description != "" { rel.Info.Description = u.Description } else { rel.Info.Description = "Uninstallation complete" diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 81d51164f..98ac44690 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -335,7 +335,7 @@ func (u *Upgrade) prepareUpgrade(ctx context.Context, name string, chart *chartv ApplyMethod: string(determineReleaseSSApplyMethod(serverSideApply)), } - if len(notesTxt) > 0 { + if notesTxt != "" { upgradedRelease.Info.Notes = notesTxt } err = validateManifest(u.cfg.KubeClient, manifestDoc.Bytes(), !u.DisableOpenAPIValidation) @@ -398,7 +398,7 @@ func (u *Upgrade) performUpgrade(ctx context.Context, originalRelease, upgradedR if isDryRun(u.DryRunStrategy) { u.cfg.Logger().Debug("dry run for release", "name", upgradedRelease.Name) - if len(u.Description) > 0 { + if u.Description != "" { upgradedRelease.Info.Description = u.Description } else { upgradedRelease.Info.Description = "Dry run complete" @@ -516,7 +516,7 @@ func (u *Upgrade) releasingUpgrade(c chan<- resultMessage, upgradedRelease *rele u.cfg.recordRelease(originalRelease) upgradedRelease.Info.Status = rcommon.StatusDeployed - if len(u.Description) > 0 { + if u.Description != "" { upgradedRelease.Info.Description = u.Description } else { upgradedRelease.Info.Description = "Upgrade complete" diff --git a/pkg/chart/v2/lint/rules/chartfile.go b/pkg/chart/v2/lint/rules/chartfile.go index f8f609280..cb58bbac0 100644 --- a/pkg/chart/v2/lint/rules/chartfile.go +++ b/pkg/chart/v2/lint/rules/chartfile.go @@ -216,7 +216,7 @@ func validateChartDependencies(cf *chart.Metadata) error { } func validateChartType(cf *chart.Metadata) error { - if len(cf.Type) > 0 && cf.APIVersion != chart.APIVersionV2 { + if cf.Type != "" && cf.APIVersion != chart.APIVersionV2 { return fmt.Errorf("chart type is not valid in apiVersion '%s'. It is valid in apiVersion '%s'", cf.APIVersion, chart.APIVersionV2) } return nil diff --git a/pkg/chart/v2/util/dependencies.go b/pkg/chart/v2/util/dependencies.go index f28a4f4b1..019cd1cda 100644 --- a/pkg/chart/v2/util/dependencies.go +++ b/pkg/chart/v2/util/dependencies.go @@ -43,7 +43,7 @@ func processDependencyConditions(reqs []*chart.Dependency, cvals common.Values, } for _, r := range reqs { for c := range strings.SplitSeq(strings.TrimSpace(r.Condition), ",") { - if len(c) > 0 { + if c != "" { // retrieve value vv, err := cvals.PathValue(cpath + c) var errNoValue common.ErrNoValue diff --git a/pkg/cli/values/options.go b/pkg/cli/values/options.go index 336dfb72b..6edfb415c 100644 --- a/pkg/cli/values/options.go +++ b/pkg/cli/values/options.go @@ -62,7 +62,7 @@ func (opts *Options) MergeValues(p getter.Providers) (map[string]any, error) { // User specified a value via --set-json for _, value := range opts.JSONValues { trimmedValue := strings.TrimSpace(value) - if len(trimmedValue) > 0 && trimmedValue[0] == '{' { + if trimmedValue != "" && trimmedValue[0] == '{' { // If value is JSON object format, parse it as map var jsonMap map[string]any if err := json.Unmarshal([]byte(trimmedValue), &jsonMap); err != nil { diff --git a/pkg/cmd/get_notes.go b/pkg/cmd/get_notes.go index 46fbeeaf5..7f8754f3c 100644 --- a/pkg/cmd/get_notes.go +++ b/pkg/cmd/get_notes.go @@ -55,7 +55,7 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if err != nil { return err } - if len(rac.Notes()) > 0 { + if rac.Notes() != "" { fmt.Fprintf(out, "NOTES:\n%s\n", rac.Notes()) } return nil diff --git a/pkg/cmd/load_plugins.go b/pkg/cmd/load_plugins.go index 474eaea2e..dee42f750 100644 --- a/pkg/cmd/load_plugins.go +++ b/pkg/cmd/load_plugins.go @@ -242,7 +242,7 @@ func addPluginCommands(plug plugin.Plugin, baseCmd *cobra.Command, cmds *pluginC return } - if len(cmds.Name) == 0 { + if cmds.Name == "" { slog.Debug("sub-command name field missing", slog.String("commandPath", baseCmd.CommandPath())) return } @@ -380,7 +380,7 @@ func pluginDynamicComp(plug plugin.Plugin, cmd *cobra.Command, args []string, to var completions []string for comp := range strings.SplitSeq(buf.String(), "\n") { // Remove any empty lines - if len(comp) > 0 { + if comp != "" { completions = append(completions, comp) } } diff --git a/pkg/cmd/package_test.go b/pkg/cmd/package_test.go index db4a2523a..5705c9b9e 100644 --- a/pkg/cmd/package_test.go +++ b/pkg/cmd/package_test.go @@ -119,7 +119,7 @@ func TestPackage(t *testing.T) { } // This is an unfortunate byproduct of the tmpdir - if v, ok := tt.flags["keyring"]; ok && len(v) > 0 { + if v, ok := tt.flags["keyring"]; ok && v != "" { tt.flags["keyring"] = filepath.Join(origDir, v) } @@ -147,7 +147,7 @@ func TestPackage(t *testing.T) { t.Fatalf("%q: expected error %q, got %q", tt.name, tt.expect, err) } - if len(tt.hasfile) > 0 { + if tt.hasfile != "" { if fi, err := os.Stat(tt.hasfile); err != nil { t.Errorf("%q: expected file %q, got err %q", tt.name, tt.hasfile, err) } else if fi.Size() == 0 { diff --git a/pkg/cmd/plugin_test.go b/pkg/cmd/plugin_test.go index 0a6435d99..476997110 100644 --- a/pkg/cmd/plugin_test.go +++ b/pkg/cmd/plugin_test.go @@ -291,7 +291,7 @@ func checkCommand(t *testing.T, plugins []*cobra.Command, tests []staticCompleti var pflags []string pp.LocalFlags().VisitAll(func(flag *pflag.Flag) { pflags = append(pflags, flag.Name) - if len(flag.Shorthand) > 0 && flag.Shorthand != flag.Name { + if flag.Shorthand != "" && flag.Shorthand != flag.Name { pflags = append(pflags, flag.Shorthand) } }) diff --git a/pkg/cmd/repo_add.go b/pkg/cmd/repo_add.go index 3fc1a7249..a7a02ef75 100644 --- a/pkg/cmd/repo_add.go +++ b/pkg/cmd/repo_add.go @@ -121,7 +121,7 @@ func (o *repoAddOptions) run(out io.Writer) error { // Acquire a file lock for process synchronization repoFileExt := filepath.Ext(o.repoFile) var lockPath string - if len(repoFileExt) > 0 && len(repoFileExt) < len(o.repoFile) { + if repoFileExt != "" && len(repoFileExt) < len(o.repoFile) { lockPath = strings.TrimSuffix(o.repoFile, repoFileExt) + ".lock" } else { lockPath = o.repoFile + ".lock" diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 3203ced25..7ee71f4ef 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -238,7 +238,7 @@ func newRootCmdWithConfig(actionConfig *action.Configuration, out io.Writer, arg cobra.CompDebugln("About to get the different kube-contexts", settings.Debug) loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - if len(settings.KubeConfig) > 0 { + if settings.KubeConfig != "" { loadingRules = &clientcmd.ClientConfigLoadingRules{ExplicitPath: settings.KubeConfig} } if config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( diff --git a/pkg/cmd/search_repo.go b/pkg/cmd/search_repo.go index 53626f1b6..9c5b1dd18 100644 --- a/pkg/cmd/search_repo.go +++ b/pkg/cmd/search_repo.go @@ -194,7 +194,7 @@ func (o *searchRepoOptions) buildIndex() (*search.Index, error) { continue } - i.AddRepo(n, ind, o.versions || len(o.version) > 0) + i.AddRepo(n, ind, o.versions || o.version != "") } return i, nil } @@ -361,7 +361,7 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell // 2- If there is some input from the user (or else we will end up // listing the entire content of the current directory which will // be too many choices for the user to find the real repos) - if includeFiles && len(completions) > 0 && len(toComplete) > 0 { + if includeFiles && len(completions) > 0 && toComplete != "" { if files, err := os.ReadDir("."); err == nil { for _, file := range files { if strings.HasPrefix(file.Name(), toComplete) { @@ -375,7 +375,7 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell // If the user didn't provide any input to completion, // we provide a hint that a path can also be used - if includeFiles && len(toComplete) == 0 { + if includeFiles && toComplete == "" { completions = append(completions, "./\tRelative path prefix to local chart", "/\tAbsolute path prefix to local chart") } cobra.CompDebugln(fmt.Sprintf("Completions after checking empty input: %v", completions), settings.Debug) diff --git a/pkg/cmd/status.go b/pkg/cmd/status.go index 705691aaf..6998e341a 100644 --- a/pkg/cmd/status.go +++ b/pkg/cmd/status.go @@ -236,7 +236,7 @@ func (s statusPrinter) WriteTable(out io.Writer) error { } // Hide notes from output - option in install and upgrades - if !s.hideNotes && len(rel.Info.Notes) > 0 { + if !s.hideNotes && rel.Info.Notes != "" { _, _ = fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(rel.Info.Notes)) } return nil diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 4a13fc5ed..eca4e3342 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -382,7 +382,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (string, *url return "", u, err } - if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 { + if u.IsAbs() && u.Host != "" && u.Path != "" { // In this case, we have to find the parent repo that contains this chart // URL. And this is an unfortunate problem, as it requires actually going // through each repo cache file and finding a matching URL. But basically diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 07b25a1eb..b3899d813 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -167,7 +167,7 @@ func TestVerifyChart(t *testing.T) { } // The verification is tested at length in the provenance package. Here, // we just want a quick sanity check that the v is not empty. - if len(v.FileHash) == 0 { + if v.FileHash == "" { t.Error("Digest missing") } } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 543f685eb..683f96007 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -441,21 +441,22 @@ func (m *Manager) safeMoveDeps(deps []*chart.Dependency, source, dest string) er fmt.Fprintln(m.Out, "Deleting outdated charts") // find all files that exist in dest that do not exist in source; delete them (outdated dependencies) for _, file := range destFiles { - if !file.IsDir() && !existsInSourceDirectory[file.Name()] { - fname := filepath.Join(dest, file.Name()) - ch, err := loader.LoadFile(fname) - if err != nil { - fmt.Fprintf(m.Out, "Could not verify %s for deletion: %s (Skipping)\n", fname, err) - continue - } - // local dependency - skip - if isLocalDependency[ch.Name()] { - continue - } - if err := os.Remove(fname); err != nil { - fmt.Fprintf(m.Out, "Could not delete %s: %s (Skipping)", fname, err) - continue - } + if file.IsDir() || existsInSourceDirectory[file.Name()] { + continue + } + fname := filepath.Join(dest, file.Name()) + ch, err := loader.LoadFile(fname) + if err != nil { + fmt.Fprintf(m.Out, "Could not verify %s for deletion: %s (Skipping)\n", fname, err) + continue + } + // local dependency - skip + if isLocalDependency[ch.Name()] { + continue + } + if err := os.Remove(fname); err != nil { + fmt.Fprintf(m.Out, "Could not delete %s: %s (Skipping)", fname, err) + continue } } @@ -728,37 +729,38 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]* } for _, cr := range repos { - if urlutil.Equal(repoURL, cr.Config.URL) { - var entry repo.ChartVersions - entry, err = findEntryByName(name, cr) - if err != nil { - // TODO: Where linting is skipped in this function we should - // refactor to remove naked returns while ensuring the same - // behavior - //nolint:nakedret - return - } - var ve *repo.ChartVersion - ve, err = findVersionedEntry(version, entry) - if err != nil { - //nolint:nakedret - return - } - url, err = repo.ResolveReferenceURL(repoURL, ve.URLs[0]) - if err != nil { - //nolint:nakedret - return - } - username = cr.Config.Username - password = cr.Config.Password - passCredentialsAll = cr.Config.PassCredentialsAll - insecureSkipTLSVerify = cr.Config.InsecureSkipTLSVerify - caFile = cr.Config.CAFile - certFile = cr.Config.CertFile - keyFile = cr.Config.KeyFile + if !urlutil.Equal(repoURL, cr.Config.URL) { + continue + } + var entry repo.ChartVersions + entry, err = findEntryByName(name, cr) + if err != nil { + // TODO: Where linting is skipped in this function we should + // refactor to remove naked returns while ensuring the same + // behavior + //nolint:nakedret + return + } + var ve *repo.ChartVersion + ve, err = findVersionedEntry(version, entry) + if err != nil { + //nolint:nakedret + return + } + url, err = repo.ResolveReferenceURL(repoURL, ve.URLs[0]) + if err != nil { //nolint:nakedret return } + username = cr.Config.Username + password = cr.Config.Password + passCredentialsAll = cr.Config.PassCredentialsAll + insecureSkipTLSVerify = cr.Config.InsecureSkipTLSVerify + caFile = cr.Config.CAFile + certFile = cr.Config.CertFile + keyFile = cr.Config.KeyFile + //nolint:nakedret + return } url, err = repo.FindChartInRepoURL(repoURL, name, m.Getters, repo.WithChartVersion(version), repo.WithClientTLS(certFile, keyFile, caFile)) if err == nil { diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index d304aea7d..1d0affd93 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -437,7 +437,7 @@ func parseTemplateSimpleErrorString(remainder string) (TraceableError, bool) { // Matches https://cs.opensource.google/go/go/+/refs/tags/go1.23.6:src/text/template/exec.go;l=141 func parseTemplateExecutingAtErrorType(remainder string) (TraceableError, bool) { if templateName, after, found := strings.Cut(remainder, ": executing "); found { - if len(after) == 0 || after[0] != '"' { + if after == "" || after[0] != '"' { return TraceableError{}, false } // find closing quote for function name diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 7b02f47ef..4e6d5c3a9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -961,7 +961,7 @@ func getManagedFieldsManager() string { } // When no manager is set and no calling application can be found it is unknown - if len(os.Args[0]) == 0 { + if os.Args[0] == "" { return "unknown" } diff --git a/pkg/kube/statuswait.go b/pkg/kube/statuswait.go index 29de0af2b..12c3e95a6 100644 --- a/pkg/kube/statuswait.go +++ b/pkg/kube/statuswait.go @@ -180,11 +180,8 @@ func (w *statusWaiter) wait(ctx context.Context, resourceList ResourceList, sw w defer cancel() resources := []object.ObjMetadata{} for _, resource := range resourceList { - switch value := AsVersioned(resource).(type) { - case *appsv1.Deployment: - if value.Spec.Paused { - continue - } + if value, ok := AsVersioned(resource).(*appsv1.Deployment); ok && value.Spec.Paused { + continue } obj, err := object.RuntimeToObjMeta(resource.Object) if err != nil { diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 8784e6c12..faf402b43 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -380,7 +380,7 @@ func TestVerify(t *testing.T) { if ver, err := signer.Verify(archiveData, sigData, filepath.Base(testChartfile)); err != nil { t.Errorf("Failed to pass verify. Err: %s", err) - } else if len(ver.FileHash) == 0 { + } else if ver.FileHash == "" { t.Error("Verification is missing hash.") } else if ver.SignedBy == nil { t.Error("No SignedBy field") diff --git a/pkg/registry/chart.go b/pkg/registry/chart.go index d70b7e912..7c41785c5 100644 --- a/pkg/registry/chart.go +++ b/pkg/registry/chart.go @@ -72,7 +72,7 @@ func generateChartOCIAnnotations(meta *chart.Metadata, creationTime string) map[ chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationVersion, meta.Version) chartOCIAnnotations = addToMap(chartOCIAnnotations, ocispec.AnnotationURL, meta.Home) - if len(creationTime) == 0 { + if creationTime == "" { creationTime = time.Now().UTC().Format(time.RFC3339) } @@ -86,11 +86,11 @@ func generateChartOCIAnnotations(meta *chart.Metadata, creationTime string) map[ var maintainerSb strings.Builder for maintainerIdx, maintainer := range meta.Maintainers { - if len(maintainer.Name) > 0 { + if maintainer.Name != "" { maintainerSb.WriteString(maintainer.Name) } - if len(maintainer.Email) > 0 { + if maintainer.Email != "" { maintainerSb.WriteString(" (") maintainerSb.WriteString(maintainer.Email) maintainerSb.WriteString(")") @@ -110,7 +110,7 @@ func generateChartOCIAnnotations(meta *chart.Metadata, creationTime string) map[ // addToMap takes an existing map and adds an item if the value is not empty func addToMap(inputMap map[string]string, newKey string, newValue string) map[string]string { // Add item to map if its - if len(strings.TrimSpace(newValue)) > 0 { + if strings.TrimSpace(newValue) != "" { inputMap[newKey] = newValue } diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 4d7da78dc..a14afdd1f 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -303,8 +303,7 @@ func ensureTLSConfig(client *auth.Client, setConfig *tls.Config) (*tls.Config, e case *http.Transport: transport = t case *LoggingTransport: - switch t := t.RoundTripper.(type) { - case *http.Transport: + if t, ok := t.RoundTripper.(*http.Transport); ok { transport = t } } diff --git a/pkg/registry/transport.go b/pkg/registry/transport.go index e4177efb3..68e4ac587 100644 --- a/pkg/registry/transport.go +++ b/pkg/registry/transport.go @@ -130,7 +130,7 @@ func logResponseBody(resp *http.Response) string { } readBody := buf.String() - if len(readBody) == 0 { + if readBody == "" { return " Response body is empty" } if containsCredentials(readBody) { diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index b02400938..35c7a0721 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -149,27 +149,28 @@ metadata: for _, out := range hs { found := false for _, expect := range data { - if out.Path == expect.path { - found = true - assert.Equal(t, expect.path, out.Path) - nameFound := false - for _, expectedName := range expect.name { - if out.Name == expectedName { - nameFound = true - } + if out.Path != expect.path { + continue + } + found = true + assert.Equal(t, expect.path, out.Path) + nameFound := false + for _, expectedName := range expect.name { + if out.Name == expectedName { + nameFound = true } - assert.True(t, nameFound, "Got unexpected name %s", out.Name) - kindFound := false - for _, expectedKind := range expect.kind { - if out.Kind == expectedKind { - kindFound = true - } + } + assert.True(t, nameFound, "Got unexpected name %s", out.Name) + kindFound := false + for _, expectedKind := range expect.kind { + if out.Kind == expectedKind { + kindFound = true } - assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) - - expectedHooks := expect.hooks[out.Name] - assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } + assert.True(t, kindFound, "Got unexpected kind %s", out.Kind) + + expectedHooks := expect.hooks[out.Name] + assert.Equal(t, expectedHooks, out.Events, "expected events: %v but got: %v", expectedHooks, out.Events) } assert.True(t, found, "Result not found: %v", out) } diff --git a/pkg/repo/v1/index.go b/pkg/repo/v1/index.go index 57e4c081f..15f72891b 100644 --- a/pkg/repo/v1/index.go +++ b/pkg/repo/v1/index.go @@ -214,7 +214,7 @@ func (i IndexFile) Get(name, version string) (*ChartVersion, error) { } // when customer inputs specific version, check whether there's an exact match first - if len(version) != 0 { + if version != "" { for _, ver := range vs { if version == ver.Version { return ver, nil @@ -229,9 +229,9 @@ func (i IndexFile) Get(name, version string) (*ChartVersion, error) { } if constraint.Check(test) { - if len(version) != 0 && !isVersionRange(version) { + if version != "" && !isVersionRange(version) { slog.Warn("unable to find exact version requested; falling back to closest available version", "chart", name, "requested", version, "selected", ver.Version) - } else if len(version) != 0 && isVersionRange(version) { + } else if version != "" && isVersionRange(version) { slog.Debug("selected version matching constraint", "chart", name, "constraint", version, "selected", ver.Version) } return ver, nil diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index a0b72bee3..c52e8aed9 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -290,7 +290,7 @@ func (t *parser) key(data map[string]any, nestedNameLevel int) (reterr error) { func set(data map[string]any, key string, val any) { // If key is empty, don't set it. - if len(key) == 0 { + if key == "" { return } data[key] = val @@ -549,7 +549,7 @@ func typedVal(v []rune, st bool) any { } // If this value does not start with zero, try parsing it to an int - if len(val) != 0 && val[0] != '0' { + if val != "" && val[0] != '0' { if iv, err := strconv.ParseInt(val, 10, 64); err == nil { return iv } From e3fbe2e9d10985fa30aeeb678c376d9556a2b6f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:33:29 +0000 Subject: [PATCH 044/161] chore(deps): bump golang.org/x/text from 0.38.0 to 0.39.0 Bumps [golang.org/x/text](https://github.com/golang/text) from 0.38.0 to 0.39.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.38.0...v0.39.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-version: 0.39.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 628b3f374..b677fce6e 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.53.0 golang.org/x/term v0.44.0 - golang.org/x/text v0.38.0 + golang.org/x/text v0.39.0 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.36.2 k8s.io/apiextensions-apiserver v0.36.2 @@ -158,13 +158,13 @@ require ( go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/mod v0.36.0 // indirect + golang.org/x/mod v0.37.0 // indirect golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.21.0 // indirect golang.org/x/sys v0.46.0 // indirect golang.org/x/time v0.15.0 // indirect - golang.org/x/tools v0.45.0 // indirect + golang.org/x/tools v0.47.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/grpc v1.80.0 // indirect diff --git a/go.sum b/go.sum index dc469fde9..27bf11eac 100644 --- a/go.sum +++ b/go.sum @@ -390,8 +390,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -450,8 +450,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -460,8 +460,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= -golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= From ca24a55c314d2fd84430d88c55ce09a391798d8e Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Wed, 8 Jul 2026 11:32:56 +0200 Subject: [PATCH 045/161] fix(ci): resolve Node 20 deprecation in govulncheck The pinned v1.0.4 used actions/checkout@v4 and actions/setup-go@v5 internally, both built on Node 20. Latest main uses v6 of both, which run on Node 24. Signed-off-by: Benoit Tigeot --- .github/workflows/govulncheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 93ab559fc..4dc8a84f5 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -30,6 +30,6 @@ jobs: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true - name: govulncheck - uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # pin@1.0.4 + uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # pin@main 2026-07-06 with: go-package: ./... From ed651de9b12ff98c0aa13985a88bca9aca0aa4fb Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Wed, 8 Jul 2026 11:58:43 +0200 Subject: [PATCH 046/161] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Benoit Tigeot --- .github/workflows/govulncheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 4dc8a84f5..5e5111432 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -30,6 +30,6 @@ jobs: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true - name: govulncheck - uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # pin@main 2026-07-06 + uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # pin@032d455 (from main 2026-07-06) with: go-package: ./... From f25f9555785b15fc7f41aa2e5e43979b1bca5021 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:00:43 -0600 Subject: [PATCH 047/161] chore(deps): bump github/codeql-action/upload-sarif (#32311) Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.3 to 4.37.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index e90e91bb3..343669859 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 with: sarif_file: results.sarif From a242855a7e2c31efd1f0f69ad1c5ae24be0563de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:00:46 -0600 Subject: [PATCH 048/161] chore(deps): bump golang.org/x/text from 0.39.0 to 0.40.0 (#32309) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.39.0 to 0.40.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.39.0...v0.40.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-version: 0.40.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index b677fce6e..2e3b11297 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.53.0 golang.org/x/term v0.44.0 - golang.org/x/text v0.39.0 + golang.org/x/text v0.40.0 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.36.2 k8s.io/apiextensions-apiserver v0.36.2 @@ -161,7 +161,7 @@ require ( golang.org/x/mod v0.37.0 // indirect golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.21.0 // indirect + golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.46.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.47.0 // indirect diff --git a/go.sum b/go.sum index 27bf11eac..3ca6d6f5e 100644 --- a/go.sum +++ b/go.sum @@ -414,8 +414,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -450,8 +450,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= -golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From ea52bdf7e2c5155d629c85aa7eb7f625eef92936 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:01:56 -0600 Subject: [PATCH 049/161] chore(deps): bump github/codeql-action/autobuild from 4.36.2 to 4.37.0 (#32305) Bumps [github/codeql-action/autobuild](https://github.com/github/codeql-action) from 4.36.2 to 4.37.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) --- updated-dependencies: - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 323b8ec5b..29ce03ddf 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # pinv4.36.2 + uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl From a71eb99db4f0c08fae21d3bfafa3bdfb6465b2a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:03:56 -0600 Subject: [PATCH 050/161] chore(deps): bump github/codeql-action/init from 4.36.2 to 4.37.0 (#32313) Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.2 to 4.37.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 29ce03ddf..13303ab16 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # pinv4.36.2 + uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. From 71901a4c7cc6280317b892341b5dde5a866c952c Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Thu, 9 Jul 2026 05:49:00 -0600 Subject: [PATCH 051/161] chore(deps): bump github/codeql-action/analyze from 4.36.2 to 4.37.0 The init and autobuild steps were bumped to 4.37.0 (#32313, #32305) but the analyze step remained at 4.36.2, causing CodeQL to fail on main with: "Loaded a configuration file for version '4.37.0', but running version '4.36.2'". Align analyze with the other codeql-action steps. Signed-off-by: Terry Howe --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 13303ab16..e87ec8ec2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # pinv4.36.2 + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 From 0fc3b9385348b0d346728de3b0969ae2a3b7d47f Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Thu, 9 Jul 2026 05:41:28 -0600 Subject: [PATCH 052/161] chore(deps): bump golang.org/x/crypto from 0.53.0 to 0.54.0 x/crypto v0.54.0 raises golang.org/x/term to v0.45.0 and golang.org/x/sys to v0.47.0 via minimum version selection. Signed-off-by: Terry Howe --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 2e3b11297..b3c6eb290 100644 --- a/go.mod +++ b/go.mod @@ -35,8 +35,8 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tetratelabs/wazero v1.12.0 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.53.0 - golang.org/x/term v0.44.0 + golang.org/x/crypto v0.54.0 + golang.org/x/term v0.45.0 golang.org/x/text v0.40.0 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.36.2 @@ -162,7 +162,7 @@ require ( golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.22.0 // indirect - golang.org/x/sys v0.46.0 // indirect + golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.47.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect diff --git a/go.sum b/go.sum index 3ca6d6f5e..06539321b 100644 --- a/go.sum +++ b/go.sum @@ -384,8 +384,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= +golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -432,8 +432,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -441,8 +441,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= From 8118a4da1ed0ba470571ee3e150e4949b373ba9c Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Thu, 9 Jul 2026 05:49:00 -0600 Subject: [PATCH 053/161] chore(deps): bump github/codeql-action/analyze from 4.36.2 to 4.37.0 The init and autobuild steps were bumped to 4.37.0 (#32313, #32305) but the analyze step remained at 4.36.2, causing CodeQL to fail on main with: "Loaded a configuration file for version '4.37.0', but running version '4.36.2'". Align analyze with the other codeql-action steps. Signed-off-by: Terry Howe --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 13303ab16..e87ec8ec2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # pinv4.36.2 + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 From 7bfcdb0fc34894ec6f1622f48608161188b2e2a8 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 10:04:48 +0200 Subject: [PATCH 054/161] fix(linters): update golangci-lint to 2.12.2 Signed-off-by: Matthieu MOREL --- .github/env | 2 +- .golangci.yml | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/env b/.github/env index 43ebdd36e..9a0c1ef4c 100644 --- a/.github/env +++ b/.github/env @@ -1,2 +1,2 @@ GOLANG_VERSION=1.26 -GOLANGCI_LINT_VERSION=v2.11.3 +GOLANGCI_LINT_VERSION=v2.12.2 diff --git a/.golangci.yml b/.golangci.yml index 1cd720d47..606613b4e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -27,7 +27,7 @@ linters: - exhaustive - fatcontext - gocritic - - gomodguard + - gomodguard_v2 - govet - ineffassign - misspell @@ -107,12 +107,11 @@ linters: - whyNoLint enable-all: true - gomodguard: + gomodguard_v2: blocked: - modules: - - github.com/evanphx/json-patch: - recommendations: - - github.com/evanphx/json-patch/v5 + - module: github.com/evanphx/json-patch + recommendations: + - github.com/evanphx/json-patch/v5 nolintlint: require-specific: true From 9662fdd73b848e04889b452335b60250414ef6db Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 11:03:22 +0200 Subject: [PATCH 055/161] refactor: enable several checks from gocritic Signed-off-by: Matthieu MOREL --- .golangci.yml | 5 ----- internal/chart/v3/lint/rules/values_test.go | 2 +- internal/chart/v3/util/create_test.go | 2 +- internal/release/v2/util/manifest.go | 2 +- internal/third_party/dep/fs/fs_test.go | 6 +++--- pkg/action/dependency.go | 2 +- pkg/action/install_test.go | 24 ++++++++++----------- pkg/action/list.go | 2 +- pkg/chart/v2/lint/rules/values_test.go | 2 +- pkg/chart/v2/util/create_test.go | 2 +- pkg/cmd/dependency_build_test.go | 2 +- pkg/cmd/repo_add_test.go | 2 +- pkg/cmd/repo_remove_test.go | 2 +- pkg/cmd/search_repo.go | 6 +++--- pkg/cmd/show_test.go | 1 - pkg/cmd/template_test.go | 2 +- pkg/downloader/cache_test.go | 4 ++-- pkg/downloader/chart_downloader_test.go | 2 +- pkg/downloader/manager.go | 2 +- pkg/engine/funcs_test.go | 2 +- pkg/getter/httpgetter_test.go | 4 ++-- pkg/helmpath/lazypath_unix_test.go | 6 +++--- pkg/kube/ready_test.go | 2 +- pkg/registry/client_scope_test.go | 4 ++-- pkg/registry/registry_test.go | 2 +- pkg/release/v1/util/manifest.go | 2 +- pkg/repo/v1/index.go | 2 +- pkg/storage/driver/sql_test.go | 14 ++++++------ pkg/storage/storage_test.go | 1 - pkg/strvals/literal_parser_test.go | 2 +- pkg/strvals/parser.go | 2 -- pkg/strvals/parser_test.go | 2 +- 32 files changed, 55 insertions(+), 62 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 1cd720d47..4cde6b1e9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -84,19 +84,14 @@ linters: gocritic: disabled-checks: - appendAssign - - appendCombine - - assignOp - badCall - commentedOutCode - - commentFormatting - deferInLoop - elseif - exposedSyncMutex - - filepathJoin - hugeParam - ifElseChain - importShadow - - nilValReturn - paramTypeCombine - ptrToRefParam - rangeValCopy diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index 36f5c403e..470904049 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -26,7 +26,7 @@ import ( "helm.sh/helm/v4/internal/test/ensure" ) -var nonExistingValuesFilePath = filepath.Join("/fake/dir", "values.yaml") +var nonExistingValuesFilePath = filepath.FromSlash("/fake/dir/values.yaml") const testSchema = ` { diff --git a/internal/chart/v3/util/create_test.go b/internal/chart/v3/util/create_test.go index abdd52a82..834ab3662 100644 --- a/internal/chart/v3/util/create_test.go +++ b/internal/chart/v3/util/create_test.go @@ -121,7 +121,7 @@ func TestCreate_Overwrite(t *testing.T) { dir := filepath.Join(tdir, "foo") - tplname := filepath.Join(dir, "templates/hpa.yaml") + tplname := filepath.Join(dir, "templates", "hpa.yaml") writeFile(tplname, []byte("FOO")) // Now re-run the create diff --git a/internal/release/v2/util/manifest.go b/internal/release/v2/util/manifest.go index 5dbcdaea5..79f651c54 100644 --- a/internal/release/v2/util/manifest.go +++ b/internal/release/v2/util/manifest.go @@ -64,7 +64,7 @@ func SplitManifests(bigFile string) map[string]string { d = strings.TrimLeftFunc(d, unicode.IsSpace) res[fmt.Sprintf(tpl, count)] = d - count = count + 1 + count++ } return res } diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index 6eed3f055..797890f9f 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -358,9 +358,9 @@ func TestCopyFileSymlink(t *testing.T) { tempdir := t.TempDir() testcases := map[string]string{ - filepath.Join("./testdata/symlinks/file-symlink"): filepath.Join(tempdir, "dst-file"), - filepath.Join("./testdata/symlinks/windows-file-symlink"): filepath.Join(tempdir, "windows-dst-file"), - filepath.Join("./testdata/symlinks/invalid-symlink"): filepath.Join(tempdir, "invalid-symlink"), + filepath.Join(".", "testdata", "symlinks", "file-symlink"): filepath.Join(tempdir, "dst-file"), + filepath.Join(".", "testdata", "symlinks", "windows-file-symlink"): filepath.Join(tempdir, "windows-dst-file"), + filepath.Join(".", "testdata", "symlinks", "invalid-symlink"): filepath.Join(tempdir, "invalid-symlink"), } for symlink, dst := range testcases { diff --git a/pkg/action/dependency.go b/pkg/action/dependency.go index 8ceca1433..895c11e63 100644 --- a/pkg/action/dependency.go +++ b/pkg/action/dependency.go @@ -201,7 +201,7 @@ func (d *Dependency) printDependencies(chartpath string, out io.Writer, c *chart // printMissing prints warnings about charts that are present on disk, but are // not in Chart.yaml. func (d *Dependency) printMissing(chartpath string, out io.Writer, reqs []*chart.Dependency) { - folder := filepath.Join(chartpath, "charts/*") + folder := filepath.Join(chartpath, "charts", "*") files, err := filepath.Glob(folder) if err != nil { fmt.Fprintln(out, err) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 0d0e58e4a..f79590670 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -868,21 +868,21 @@ func TestInstallReleaseOutputDir(t *testing.T) { t.Fatalf("Failed install: %s", err) } - _, err = os.Stat(filepath.Join(dir, "hello/templates/goodbye")) + _, err = os.Stat(filepath.Join(dir, "hello", "templates", "goodbye")) req.NoError(err) - _, err = os.Stat(filepath.Join(dir, "hello/templates/hello")) + _, err = os.Stat(filepath.Join(dir, "hello", "templates", "hello")) req.NoError(err) - _, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials")) + _, err = os.Stat(filepath.Join(dir, "hello", "templates", "with-partials")) req.NoError(err) - _, err = os.Stat(filepath.Join(dir, "hello/templates/rbac")) + _, err = os.Stat(filepath.Join(dir, "hello", "templates", "rbac")) req.NoError(err) - test.AssertGoldenFile(t, filepath.Join(dir, "hello/templates/rbac"), "rbac.txt") + test.AssertGoldenFile(t, filepath.Join(dir, "hello", "templates", "rbac"), "rbac.txt") - _, err = os.Stat(filepath.Join(dir, "hello/templates/empty")) + _, err = os.Stat(filepath.Join(dir, "hello", "templates", "empty")) is.ErrorIs(err, fs.ErrNotExist) } @@ -905,21 +905,21 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { t.Fatalf("Failed install: %s", err) } - _, err = os.Stat(filepath.Join(newDir, "hello/templates/goodbye")) + _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "goodbye")) req.NoError(err) - _, err = os.Stat(filepath.Join(newDir, "hello/templates/hello")) + _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "hello")) req.NoError(err) - _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials")) + _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "with-partials")) req.NoError(err) - _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac")) + _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "rbac")) req.NoError(err) - test.AssertGoldenFile(t, filepath.Join(newDir, "hello/templates/rbac"), "rbac.txt") + test.AssertGoldenFile(t, filepath.Join(newDir, "hello", "templates", "rbac"), "rbac.txt") - _, err = os.Stat(filepath.Join(newDir, "hello/templates/empty")) + _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "empty")) is.ErrorIs(err, fs.ErrNotExist) } diff --git a/pkg/action/list.go b/pkg/action/list.go index 06727bd9a..a055f760d 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -178,7 +178,7 @@ func (l *List) Run() ([]ri.Releaser, error) { } if results == nil { - return results, nil + return nil, nil } rresults, err := releaseListToV1List(results) diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index 36f5c403e..470904049 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -26,7 +26,7 @@ import ( "helm.sh/helm/v4/internal/test/ensure" ) -var nonExistingValuesFilePath = filepath.Join("/fake/dir", "values.yaml") +var nonExistingValuesFilePath = filepath.FromSlash("/fake/dir/values.yaml") const testSchema = ` { diff --git a/pkg/chart/v2/util/create_test.go b/pkg/chart/v2/util/create_test.go index 967972fc8..367b755d9 100644 --- a/pkg/chart/v2/util/create_test.go +++ b/pkg/chart/v2/util/create_test.go @@ -121,7 +121,7 @@ func TestCreate_Overwrite(t *testing.T) { dir := filepath.Join(tdir, "foo") - tplname := filepath.Join(dir, "templates/hpa.yaml") + tplname := filepath.Join(dir, "templates", "hpa.yaml") writeFile(tplname, []byte("FOO")) // Now re-run the create diff --git a/pkg/cmd/dependency_build_test.go b/pkg/cmd/dependency_build_test.go index a3473301d..7b3bea28a 100644 --- a/pkg/cmd/dependency_build_test.go +++ b/pkg/cmd/dependency_build_test.go @@ -72,7 +72,7 @@ func TestDependencyBuildCmd(t *testing.T) { } // Make sure the actual file got downloaded. - expect := filepath.Join(rootDir, chartname, "charts/reqtest-0.1.0.tgz") + expect := filepath.Join(rootDir, chartname, "charts", "reqtest-0.1.0.tgz") if _, err := os.Stat(expect); err != nil { t.Fatal(err) } diff --git a/pkg/cmd/repo_add_test.go b/pkg/cmd/repo_add_test.go index 1290d3862..ed677f98a 100644 --- a/pkg/cmd/repo_add_test.go +++ b/pkg/cmd/repo_add_test.go @@ -49,7 +49,7 @@ func TestRepoAddCmd(t *testing.T) { ) defer srv2.Stop() - tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data") + tmpdir := filepath.Join(t.TempDir(), "path-component.yaml", "data") if err := os.MkdirAll(tmpdir, 0o777); err != nil { t.Fatal(err) } diff --git a/pkg/cmd/repo_remove_test.go b/pkg/cmd/repo_remove_test.go index 79778e75e..3b0072a68 100644 --- a/pkg/cmd/repo_remove_test.go +++ b/pkg/cmd/repo_remove_test.go @@ -171,7 +171,7 @@ func TestRepoRemoveCompletion(t *testing.T) { rootDir := t.TempDir() repoFile := filepath.Join(rootDir, "repositories.yaml") - repoCache := filepath.Join(rootDir, "cache/") + repoCache := filepath.Join(rootDir, "cache") var testRepoNames = []string{"foo", "bar", "baz"} diff --git a/pkg/cmd/search_repo.go b/pkg/cmd/search_repo.go index 9c5b1dd18..348ca12b6 100644 --- a/pkg/cmd/search_repo.go +++ b/pkg/cmd/search_repo.go @@ -382,15 +382,15 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell directive := cobra.ShellCompDirectiveDefault if noFile { - directive = directive | cobra.ShellCompDirectiveNoFileComp + directive |= cobra.ShellCompDirectiveNoFileComp } if noSpace { - directive = directive | cobra.ShellCompDirectiveNoSpace + directive |= cobra.ShellCompDirectiveNoSpace } if !includeFiles { // If we should not include files in the completions, // we should disable file completion - directive = directive | cobra.ShellCompDirectiveNoFileComp + directive |= cobra.ShellCompDirectiveNoFileComp } return completions, directive } diff --git a/pkg/cmd/show_test.go b/pkg/cmd/show_test.go index 5da2626d3..e24b8c442 100644 --- a/pkg/cmd/show_test.go +++ b/pkg/cmd/show_test.go @@ -76,7 +76,6 @@ func TestShowPreReleaseChart(t *testing.T) { outdir, contentTmp, ) - //_, out, err := executeActionCommand(cmd) _, _, err := executeActionCommand(cmd) if err != nil { if tt.fail { diff --git a/pkg/cmd/template_test.go b/pkg/cmd/template_test.go index b43151413..d508a0505 100644 --- a/pkg/cmd/template_test.go +++ b/pkg/cmd/template_test.go @@ -40,7 +40,7 @@ func TestTemplateCmd(t *testing.T) { }, { name: "check values files", - cmd: fmt.Sprintf("template '%s' --values '%s'", chartPath, filepath.Join(chartPath, "/charts/subchartA/values.yaml")), + cmd: fmt.Sprintf("template '%s' --values '%s'", chartPath, filepath.Join(chartPath, "charts", "subchartA", "values.yaml")), golden: "output/template-values-files.txt", }, { diff --git a/pkg/downloader/cache_test.go b/pkg/downloader/cache_test.go index d8a2c3768..49a7adc5d 100644 --- a/pkg/downloader/cache_test.go +++ b/pkg/downloader/cache_test.go @@ -117,6 +117,6 @@ func TestDiskCache_fileName(t *testing.T) { cache := &DiskCache{Root: "/tmp/cache"} key := sha256.Sum256([]byte("some data")) - assert.Equal(t, filepath.Join("/tmp/cache", "13", "1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee.chart"), cache.fileName(key, CacheChart)) - assert.Equal(t, filepath.Join("/tmp/cache", "13", "1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee.prov"), cache.fileName(key, CacheProv)) + assert.Equal(t, filepath.FromSlash("/tmp/cache/13/1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee.chart"), cache.fileName(key, CacheChart)) + assert.Equal(t, filepath.FromSlash("/tmp/cache/13/1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee.prov"), cache.fileName(key, CacheProv)) } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index b3899d813..a4de2f5e3 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -278,7 +278,7 @@ func TestDownloadTo_TLS(t *testing.T) { getter.WithTLSClientConfig( "", "", - filepath.Join("../../testdata/rootca.crt"), + filepath.FromSlash("../../testdata/rootca.crt"), ), }, } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 683f96007..e99a826b4 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -764,7 +764,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]* } url, err = repo.FindChartInRepoURL(repoURL, name, m.Getters, repo.WithChartVersion(version), repo.WithClientTLS(certFile, keyFile, caFile)) if err == nil { - return url, username, password, false, false, "", "", "", err + return url, username, password, false, false, "", "", "", nil } err = fmt.Errorf("chart %s not found in %s: %w", name, repoURL, err) return url, username, password, false, false, "", "", "", err diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index 37f79478c..bc541339b 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -28,7 +28,7 @@ import ( ) func TestFuncs(t *testing.T) { - //TODO write tests for failure cases + // TODO write tests for failure cases tests := []struct { tpl, expect string vars any diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 57bd255b3..d7ba770b3 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -225,7 +225,7 @@ func TestDownload(t *testing.T) { // A different host is provided for the WithURL from the one used for Get u2, _ := url.ParseRequestURI(crossAuthSrv.URL) host := strings.Split(u2.Host, ":") - host[0] = host[0] + "a" + host[0] += "a" u2.Host = strings.Join(host, ":") httpgetter, err = NewHTTPGetter( WithURL(u2.String()), @@ -260,7 +260,7 @@ func TestDownload(t *testing.T) { // A different host is provided for the WithURL from the one used for Get u2, _ = url.ParseRequestURI(crossAuthSrv.URL) host = strings.Split(u2.Host, ":") - host[0] = host[0] + "a" + host[0] += "a" u2.Host = strings.Join(host, ":") httpgetter, err = NewHTTPGetter( WithURL(u2.String()), diff --git a/pkg/helmpath/lazypath_unix_test.go b/pkg/helmpath/lazypath_unix_test.go index 6f8c6c2e8..084758a21 100644 --- a/pkg/helmpath/lazypath_unix_test.go +++ b/pkg/helmpath/lazypath_unix_test.go @@ -38,7 +38,7 @@ func TestDataPath(t *testing.T) { t.Setenv(xdg.DataHomeEnvVar, "/tmp") - expected = filepath.Join("/tmp", appName, testFile) + expected = filepath.FromSlash("/tmp/" + appName + "/" + testFile) assert.Equal(t, expected, lazy.dataPath(testFile)) } @@ -50,7 +50,7 @@ func TestConfigPath(t *testing.T) { t.Setenv(xdg.ConfigHomeEnvVar, "/tmp") - expected = filepath.Join("/tmp", appName, testFile) + expected = filepath.FromSlash("/tmp/" + appName + "/" + testFile) assert.Equal(t, expected, lazy.configPath(testFile)) } @@ -62,7 +62,7 @@ func TestCachePath(t *testing.T) { t.Setenv(xdg.CacheHomeEnvVar, "/tmp") - expected = filepath.Join("/tmp", appName, testFile) + expected = filepath.FromSlash("/tmp/" + appName + "/" + testFile) assert.Equal(t, expected, lazy.cachePath(testFile)) } diff --git a/pkg/kube/ready_test.go b/pkg/kube/ready_test.go index 3b80e95d2..fc3ac9409 100644 --- a/pkg/kube/ready_test.go +++ b/pkg/kube/ready_test.go @@ -213,7 +213,7 @@ func Test_ReadyChecker_IsReady_Deployment(t *testing.T) { wantErr: true, }, { - name: "IsReady Deployments", //TODO fix this one + name: "IsReady Deployments", // TODO fix this one fields: fields{ client: fake.NewClientset(), checkJobs: true, diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index 5f121f048..a790c27a7 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -76,7 +76,7 @@ func (suite *RegistryScopeTestSuite) Test_1_Check_Push_Request_Scope() { _, err = suite.RegistryClient.Push(chartData, ref, PushOptCreationTime(testingChartCreationTime)) suite.Require().Error(err, "error pushing good ref because auth server doesn't give proper token") - //check the url that authentication server received + // check the url that authentication server received select { case urlStr := <-requestURL: u, err := url.Parse(urlStr) @@ -122,7 +122,7 @@ func (suite *RegistryScopeTestSuite) Test_2_Check_Pull_Request_Scope() { _, err = suite.RegistryClient.Pull(ref) suite.Require().Error(err, "error pulling a simple chart because auth server doesn't give proper token") - //check the url that authentication server received + // check the url that authentication server received select { case urlStr := <-requestURL: u, err := url.Parse(urlStr) diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index afcf88db5..44af191b1 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -150,7 +150,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.Require().NoError(err, "no error finding free port for test auth server") defer ln.Close() - //set test auth server host + // set test auth server host suite.AuthServerHost = ln.Addr().String() config.Auth = configuration.Auth{ diff --git a/pkg/release/v1/util/manifest.go b/pkg/release/v1/util/manifest.go index fa26f6256..4efb6b3e4 100644 --- a/pkg/release/v1/util/manifest.go +++ b/pkg/release/v1/util/manifest.go @@ -64,7 +64,7 @@ func SplitManifests(bigFile string) map[string]string { d = strings.TrimLeftFunc(d, unicode.IsSpace) res[fmt.Sprintf(tpl, count)] = d - count = count + 1 + count++ } return res } diff --git a/pkg/repo/v1/index.go b/pkg/repo/v1/index.go index 15f72891b..839a4cca9 100644 --- a/pkg/repo/v1/index.go +++ b/pkg/repo/v1/index.go @@ -318,7 +318,7 @@ func IndexDirectory(dir, baseURL string) (*IndexFile, error) { if err != nil { return nil, err } - moreArchives, err := filepath.Glob(filepath.Join(dir, "**/*.tgz")) + moreArchives, err := filepath.Glob(filepath.Join(dir, "**", "*.tgz")) if err != nil { return nil, err } diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index 4b4686b66..6044ce3c6 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -112,12 +112,14 @@ func TestSQLGet(t *testing.T) { func TestSQLList(t *testing.T) { releases := []*rspb.Release{} - releases = append(releases, releaseStub("key-1", 1, "default", common.StatusUninstalled)) - releases = append(releases, releaseStub("key-2", 1, "default", common.StatusUninstalled)) - releases = append(releases, releaseStub("key-3", 1, "default", common.StatusDeployed)) - releases = append(releases, releaseStub("key-4", 1, "default", common.StatusDeployed)) - releases = append(releases, releaseStub("key-5", 1, "default", common.StatusSuperseded)) - releases = append(releases, releaseStub("key-6", 1, "default", common.StatusSuperseded)) + releases = append(releases, + releaseStub("key-1", 1, "default", common.StatusUninstalled), + releaseStub("key-2", 1, "default", common.StatusUninstalled), + releaseStub("key-3", 1, "default", common.StatusDeployed), + releaseStub("key-4", 1, "default", common.StatusDeployed), + releaseStub("key-5", 1, "default", common.StatusSuperseded), + releaseStub("key-6", 1, "default", common.StatusSuperseded), + ) sqlDriver, mock := newTestFixtureSQL(t) diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index ec57ae311..32f926e08 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -324,7 +324,6 @@ func (d *MaxHistoryMockDriver) Name() string { } func TestMaxHistoryErrorHandling(t *testing.T) { - //func TestStorageRemoveLeastRecentWithError(t *testing.T) { storage := Init(NewMaxHistoryMockDriver(driver.NewMemory())) storage.MaxHistory = 1 diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index aab8e1b73..6c22a732b 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -422,7 +422,7 @@ func TestParseLiteralNestedLevels(t *testing.T) { for i := 1; i <= MaxNestedNameLevel+2; i++ { tmpStr := fmt.Sprintf("name%d", i) if i <= MaxNestedNameLevel+1 { - tmpStr = tmpStr + "." + tmpStr += "." } keyMultipleNestedLevels.WriteString(tmpStr) } diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index c52e8aed9..d74e46986 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -190,8 +190,6 @@ func (t *parser) key(data map[string]any, nestedNameLevel int) (reterr error) { return err } return fmt.Errorf("key %q has no value", string(k)) - //set(data, string(k), "") - //return err case last == '[': // We are in a list index context, so we need to set an index. i, err := t.keyIndex() diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 1b73ae16a..e68bc4e19 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -750,7 +750,7 @@ func TestParseSetNestedLevels(t *testing.T) { for i := 1; i <= MaxNestedNameLevel+2; i++ { tmpStr := fmt.Sprintf("name%d", i) if i <= MaxNestedNameLevel+1 { - tmpStr = tmpStr + "." + tmpStr += "." } keyMultipleNestedLevels.WriteString(tmpStr) } From 16787d65f5091cf5c5e4f2884ef0027ada117465 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 09:11:55 +0200 Subject: [PATCH 056/161] feat(linters): add new revive rules for better code quality Signed-off-by: Matthieu MOREL --- .golangci.yml | 10 +++++ internal/chart/v3/loader/load_test.go | 27 +++++-------- internal/chart/v3/util/save.go | 9 ++--- internal/plugin/installer/local_installer.go | 9 ++--- internal/plugin/runtime_subprocess.go | 6 +-- internal/third_party/dep/fs/fs.go | 31 +++++++-------- pkg/action/action.go | 7 ++-- pkg/action/upgrade.go | 7 ++-- pkg/chart/v2/loader/load_test.go | 19 ++++----- pkg/chart/v2/util/save.go | 9 ++--- pkg/cmd/install.go | 41 ++++++++++---------- pkg/cmd/upgrade.go | 39 +++++++++---------- pkg/downloader/manager.go | 23 +++++------ pkg/registry/client.go | 5 +-- pkg/storage/driver/sql.go | 6 +-- 15 files changed, 113 insertions(+), 135 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 1cd720d47..e839ea6a9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -122,6 +122,16 @@ linters: enable-default-rules: true max-open-files: 2048 rules: + - name: early-return + arguments: + - "preserve-scope" + - name: if-return + - name: indent-error-flow + arguments: + - "preserve-scope" + - name: superfluous-else + arguments: + - "preserve-scope" - name: unnecessary-format - name: var-naming arguments: diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index a493104bf..1c5845da6 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -31,6 +31,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/pkg/chart/common" "helm.sh/helm/v4/pkg/chart/loader/archive" @@ -100,41 +102,30 @@ func TestBomTestData(t *testing.T) { } archive, err := os.ReadFile("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") unzipped, err := gzip.NewReader(bytes.NewReader(archive)) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") defer unzipped.Close() for _, testFile := range testFiles { data := make([]byte, 3) err := unzipped.Reset(bytes.NewReader(archive)) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() if errors.Is(err, io.EOF) { break } - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") if file != nil && strings.EqualFold(file.Name, testFile) { _, err := tr.Read(data) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } else { + if err == nil { break } + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) } } - if !bytes.Equal(data, utf8bom) { - t.Fatalf("Test file has no BOM or is invalid: frobnitz_with_bom.tgz/%s", testFile) - } + require.Truef(t, bytes.Equal(data, utf8bom), "Test file has no BOM or is invalid: frobnitz_with_bom.tgz/%s", testFile) } } diff --git a/internal/chart/v3/util/save.go b/internal/chart/v3/util/save.go index 942e736ed..09235c1ea 100644 --- a/internal/chart/v3/util/save.go +++ b/internal/chart/v3/util/save.go @@ -114,13 +114,12 @@ func Save(c *chart.Chart, outDir string) (string, error) { filename = filepath.Join(outDir, filename) dir := filepath.Dir(filename) if stat, err := os.Stat(dir); err != nil { - if errors.Is(err, fs.ErrNotExist) { - if err2 := os.MkdirAll(dir, 0o755); err2 != nil { - return "", err2 - } - } else { + if !errors.Is(err, fs.ErrNotExist) { return "", fmt.Errorf("stat %s: %w", dir, err) } + if err2 := os.MkdirAll(dir, 0o755); err2 != nil { + return "", err2 + } } else if !stat.IsDir() { return "", fmt.Errorf("is not a directory: %s", dir) } diff --git a/internal/plugin/installer/local_installer.go b/internal/plugin/installer/local_installer.go index 8d067612f..a7a6caa14 100644 --- a/internal/plugin/installer/local_installer.go +++ b/internal/plugin/installer/local_installer.go @@ -204,14 +204,13 @@ func (i *LocalInstaller) GetVerificationData() (archiveData, provData []byte, fi provFile := i.Source + ".prov" i.provData, err = os.ReadFile(provFile) if err != nil { - if os.IsNotExist(err) { - // If provenance file doesn't exist, set provData to nil - // The verification logic will handle this gracefully - i.provData = nil - } else { + if !os.IsNotExist(err) { // If file exists but can't be read (permissions, etc), return error return nil, nil, "", fmt.Errorf("failed to access provenance file %s: %w", provFile, err) } + // If provenance file doesn't exist, set provData to nil + // The verification logic will handle this gracefully + i.provData = nil } } diff --git a/internal/plugin/runtime_subprocess.go b/internal/plugin/runtime_subprocess.go index 3c0af4a4e..b921587c1 100644 --- a/internal/plugin/runtime_subprocess.go +++ b/internal/plugin/runtime_subprocess.go @@ -125,11 +125,7 @@ func (r *SubprocessPluginRuntime) InvokeWithEnv(main string, argv []string, env cmd.Stdout = stdout cmd.Stderr = stderr - if err := executeCmd(cmd, r.metadata.Name); err != nil { - return err - } - - return nil + return executeCmd(cmd, r.metadata.Name) } func (r *SubprocessPluginRuntime) InvokeHook(event string) error { diff --git a/internal/third_party/dep/fs/fs.go b/internal/third_party/dep/fs/fs.go index 2607c73ac..4a8a736f7 100644 --- a/internal/third_party/dep/fs/fs.go +++ b/internal/third_party/dep/fs/fs.go @@ -156,24 +156,23 @@ func CopyFile(src, dst string) (err error) { if sym, err := IsSymlink(src); err != nil { return fmt.Errorf("symlink check failed: %w", err) } else if sym { - if err := cloneSymlink(src, dst); err != nil { - if runtime.GOOS == "windows" { - // If cloning the symlink fails on Windows because the user - // does not have the required privileges, ignore the error and - // fall back to copying the file contents. - // - // ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522): - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx - lerr := &os.LinkError{} - if errors.As(err, &lerr) && !errors.Is(lerr.Err, syscall.Errno(1314)) { - return err - } - } else { - return err - } - } else { + err := cloneSymlink(src, dst) + if err == nil { return nil } + if runtime.GOOS != "windows" { + return err + } + // If cloning the symlink fails on Windows because the user + // does not have the required privileges, ignore the error and + // fall back to copying the file contents. + // + // ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522): + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx + lerr := &os.LinkError{} + if errors.As(err, &lerr) && !errors.Is(lerr.Err, syscall.Errno(1314)) { + return err + } } in, err := os.Open(src) diff --git a/pkg/action/action.go b/pkg/action/action.go index 8105083f9..bcc91816c 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -551,12 +551,11 @@ func (cfg *Configuration) getCapabilities() (*common.Capabilities, error) { // See https://github.com/kubernetes/kubernetes/issues/72051#issuecomment-521157642 apiVersions, err := GetVersionSet(dc) if err != nil { - if discovery.IsGroupDiscoveryFailedError(err) { - cfg.Logger().Warn("the kubernetes server has an orphaned API service", slog.Any("error", err)) - cfg.Logger().Warn("to fix this, kubectl delete apiservice ") - } else { + if !discovery.IsGroupDiscoveryFailedError(err) { return nil, fmt.Errorf("could not get apiVersions from Kubernetes: %w", err) } + cfg.Logger().Warn("the kubernetes server has an orphaned API service", slog.Any("error", err)) + cfg.Logger().Warn("to fix this, kubectl delete apiservice ") } cfg.Capabilities = &common.Capabilities{ diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 98ac44690..7f66ceefb 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -261,12 +261,11 @@ func (u *Upgrade) prepareUpgrade(ctx context.Context, name string, chart *chartv return nil, nil, false, cerr } if err != nil { - if errors.Is(err, driver.ErrNoDeployedReleases) && - (lastRelease.Info.Status == rcommon.StatusFailed || lastRelease.Info.Status == rcommon.StatusSuperseded) { - currentRelease = lastRelease - } else { + if !errors.Is(err, driver.ErrNoDeployedReleases) || + (lastRelease.Info.Status != rcommon.StatusFailed && lastRelease.Info.Status != rcommon.StatusSuperseded) { return nil, nil, false, err } + currentRelease = lastRelease } } diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index e422c30de..46d17e899 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -31,6 +31,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" "helm.sh/helm/v4/pkg/chart/loader/archive" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -111,30 +113,23 @@ func TestBomTestData(t *testing.T) { for _, testFile := range testFiles { data := make([]byte, 3) err := unzipped.Reset(bytes.NewReader(archive)) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() if errors.Is(err, io.EOF) { break } - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") if file != nil && strings.EqualFold(file.Name, testFile) { _, err := tr.Read(data) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } else { + if err == nil { break } + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) } } - if !bytes.Equal(data, utf8bom) { - t.Fatalf("Test file has no BOM or is invalid: frobnitz_with_bom.tgz/%s", testFile) - } + require.Truef(t, bytes.Equal(data, utf8bom), "Test file has no BOM or is invalid: frobnitz_with_bom.tgz/%s", testFile) } } diff --git a/pkg/chart/v2/util/save.go b/pkg/chart/v2/util/save.go index d8189c8bf..5444ca218 100644 --- a/pkg/chart/v2/util/save.go +++ b/pkg/chart/v2/util/save.go @@ -114,13 +114,12 @@ func Save(c *chart.Chart, outDir string) (string, error) { filename = filepath.Join(outDir, filename) dir := filepath.Dir(filename) if stat, err := os.Stat(dir); err != nil { - if errors.Is(err, fs.ErrNotExist) { - if err2 := os.MkdirAll(dir, 0o755); err2 != nil { - return "", err2 - } - } else { + if !errors.Is(err, fs.ErrNotExist) { return "", fmt.Errorf("stat %s: %w", dir, err) } + if err2 := os.MkdirAll(dir, 0o755); err2 != nil { + return "", err2 + } } else if !stat.IsDir() { return "", fmt.Errorf("is not a directory: %s", dir) } diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index 832968ff0..c7aa2c542 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -301,29 +301,28 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options // As of Helm 2.4.0, this is treated as a stopping condition: // https://github.com/helm/helm/issues/2209 if err := action.CheckDependencies(chartRequested, req); err != nil { - if client.DependencyUpdate { - man := &downloader.Manager{ - Out: out, - ChartPath: cp, - Keyring: client.Keyring, - SkipUpdate: false, - Getters: p, - RepositoryConfig: settings.RepositoryConfig, - RepositoryCache: settings.RepositoryCache, - ContentCache: settings.ContentCache, - Debug: settings.Debug, - RegistryClient: client.GetRegistryClient(), - } - if err := man.Update(); err != nil { - return nil, err - } - // Reload the chart with the updated Chart.lock file. - if chartRequested, err = loader.Load(cp); err != nil { - return nil, fmt.Errorf("failed reloading chart after repo update: %w", err) - } - } else { + if !client.DependencyUpdate { return nil, fmt.Errorf("an error occurred while checking for chart dependencies. You may need to run 'helm dependency build' to fetch missing dependencies: %w", err) } + man := &downloader.Manager{ + Out: out, + ChartPath: cp, + Keyring: client.Keyring, + SkipUpdate: false, + Getters: p, + RepositoryConfig: settings.RepositoryConfig, + RepositoryCache: settings.RepositoryCache, + ContentCache: settings.ContentCache, + Debug: settings.Debug, + RegistryClient: client.GetRegistryClient(), + } + if err := man.Update(); err != nil { + return nil, err + } + // Reload the chart with the updated Chart.lock file. + if chartRequested, err = loader.Load(cp); err != nil { + return nil, fmt.Errorf("failed reloading chart after repo update: %w", err) + } } } diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index 9ec4f4ef2..a6aa96129 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -206,28 +206,27 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if req := ac.MetaDependencies(); len(req) > 0 { if err := action.CheckDependencies(ch, req); err != nil { err = fmt.Errorf("an error occurred while checking for chart dependencies. You may need to run 'helm dependency build' to fetch missing dependencies: %w", err) - if client.DependencyUpdate { - man := &downloader.Manager{ - Out: out, - ChartPath: chartPath, - Keyring: client.Keyring, - SkipUpdate: false, - Getters: p, - RepositoryConfig: settings.RepositoryConfig, - RepositoryCache: settings.RepositoryCache, - ContentCache: settings.ContentCache, - Debug: settings.Debug, - } - if err := man.Update(); err != nil { - return err - } - // Reload the chart with the updated Chart.lock file. - if ch, err = loader.Load(chartPath); err != nil { - return fmt.Errorf("failed reloading chart after repo update: %w", err) - } - } else { + if !client.DependencyUpdate { return err } + man := &downloader.Manager{ + Out: out, + ChartPath: chartPath, + Keyring: client.Keyring, + SkipUpdate: false, + Getters: p, + RepositoryConfig: settings.RepositoryConfig, + RepositoryCache: settings.RepositoryCache, + ContentCache: settings.ContentCache, + Debug: settings.Debug, + } + if err := man.Update(); err != nil { + return err + } + // Reload the chart with the updated Chart.lock file. + if ch, err = loader.Load(chartPath); err != nil { + return fmt.Errorf("failed reloading chart after repo update: %w", err) + } } } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 683f96007..e5c015f24 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -118,16 +118,15 @@ func (m *Manager) Build() error { } if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest { + if c.Metadata.APIVersion != chart.APIVersionV1 { + return errors.New("the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies with 'helm dependency update'") + } // If lock digest differs and chart is apiVersion v1, it maybe because the lock was built // with Helm 2 and therefore should be checked with Helm v2 hash // Fix for: https://github.com/helm/helm/issues/7233 - if c.Metadata.APIVersion == chart.APIVersionV1 { - log.Println("warning: a valid Helm v3 hash was not found. Checking against Helm v2 hash...") - if v2Sum != lock.Digest { - return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies") - } - } else { - return errors.New("the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies with 'helm dependency update'") + log.Println("warning: a valid Helm v3 hash was not found. Checking against Helm v2 hash...") + if v2Sum != lock.Digest { + return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies") } } @@ -365,16 +364,12 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { } // TODO: this should probably be refactored to be a []error, so we can capture and provide more information rather than "last error wins". - if saveError == nil { - // now we can move all downloaded charts to destPath and delete outdated dependencies - if err := m.safeMoveDeps(deps, tmpPath, destPath); err != nil { - return err - } - } else { + if saveError != nil { fmt.Fprintln(m.Out, "Save error occurred: ", saveError) return saveError } - return nil + // now we can move all downloaded charts to destPath and delete outdated dependencies + return m.safeMoveDeps(deps, tmpPath, destPath) } func parseOCIRef(chartRef string) (string, string, error) { diff --git a/pkg/registry/client.go b/pkg/registry/client.go index a14afdd1f..7a1c8f449 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -484,12 +484,11 @@ func (c *Client) processChartPull(genericResult *GenericPullResult, operation *p var provMissing bool if operation.withProv && provDescriptor == nil { - if operation.ignoreMissingProv { - provMissing = true - } else { + if !operation.ignoreMissingProv { return nil, fmt.Errorf("manifest does not contain a layer with mediatype %s", ProvLayerMediaType) } + provMissing = true } // Build chart-specific result diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index f3dd053a2..88d24123d 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -404,12 +404,12 @@ func (s *SQL) Query(labels map[string]string) ([]release.Releaser, error) { } sort.Strings(keys) for _, key := range keys { - if _, ok := labelMap[key]; ok { - sb = sb.Where(sq.Eq{key: labels[key]}) - } else { + _, ok := labelMap[key] + if !ok { s.Logger().Debug("unknown label", "key", key) return nil, fmt.Errorf("unknown label %s", key) } + sb = sb.Where(sq.Eq{key: labels[key]}) } // If a namespace was specified, we only list releases from that namespace From a91e9f6a249533cfd8fdb98cbd909ecb16bbc813 Mon Sep 17 00:00:00 2001 From: Akanksha Trehun <146705736+magic-peach@users.noreply.github.com> Date: Fri, 10 Jul 2026 17:00:53 +0530 Subject: [PATCH 057/161] fix(Makefile): update outdated .sha256 comment for Helm v4 (#32323) Signed-off-by: Akanksha Trehun --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 81b149a68..5a9c792bb 100644 --- a/Makefile +++ b/Makefile @@ -200,11 +200,10 @@ sign: # The contents of the .sha256sum file are compatible with tools like # shasum. For example, using the following command will verify -# the file helm-3.1.0-rc.1-darwin-amd64.tar.gz: -# shasum -a 256 -c helm-3.1.0-rc.1-darwin-amd64.tar.gz.sha256sum +# the file helm-4.0.0-darwin-amd64.tar.gz: +# shasum -a 256 -c helm-4.0.0-darwin-amd64.tar.gz.sha256sum # The .sha256 files hold only the hash and are not compatible with -# verification tools like shasum or sha256sum. This method and file can be -# removed in Helm v4. +# verification tools like shasum or sha256sum. .PHONY: checksum checksum: for f in $$(ls _dist/*.{gz,zip} 2>/dev/null) ; do \ From cfa3b24fe6c2a0e4bf22887cc1051d7674c6b348 Mon Sep 17 00:00:00 2001 From: Akanksha Trehun <146705736+magic-peach@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:02:08 +0530 Subject: [PATCH 058/161] fix: remove trailing whitespace in .golangci.yml (#32325) Signed-off-by: Akanksha Trehun --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 1cd720d47..b820e25ae 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -47,7 +47,7 @@ linters: - whitespace exclusions: - + generated: lax presets: From 7b9a5c8911c7aa53eab1bfde995c63ff626a7ca4 Mon Sep 17 00:00:00 2001 From: Akanksha Trehun <146705736+magic-peach@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:05:23 +0530 Subject: [PATCH 059/161] fix: add missing https:// to Oracle link in ADOPTERS.md (#32324) Signed-off-by: Akanksha Trehun --- ADOPTERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ADOPTERS.md b/ADOPTERS.md index a83519fea..4efc14e1c 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -12,7 +12,7 @@ - [New Relic](https://www.newrelic.com) - [Octopus Deploy](https://octopus.com/) - [Omnistrate](https://omnistrate.com) -- [Oracle](www.oracle.com) +- [Oracle](https://www.oracle.com) - [Percona](https://www.percona.com) - [Qovery](https://www.qovery.com/) - [Samsung SDS](https://www.samsungsds.com/) From bfebbb7c1a3cea951dcc33d3253492f6a6df4eb2 Mon Sep 17 00:00:00 2001 From: Matheus Pimenta Date: Fri, 10 Jul 2026 16:32:48 +0100 Subject: [PATCH 060/161] Fix vanishing empty lines Signed-off-by: Matheus Pimenta --- internal/release/v2/util/manifest.go | 2 +- internal/release/v2/util/manifest_test.go | 32 ++++++++++++------- pkg/action/action_test.go | 15 +++++---- pkg/action/testdata/rbac.txt | 2 ++ pkg/cmd/testdata/output/object-order.txt | 26 +++++++++++++++ .../output/template-show-only-glob.txt | 4 +++ .../output/template-show-only-multiple.txt | 3 ++ .../output/template-show-only-one.txt | 1 + pkg/release/v1/util/manifest.go | 2 +- pkg/release/v1/util/manifest_test.go | 32 ++++++++++++------- 10 files changed, 89 insertions(+), 30 deletions(-) diff --git a/internal/release/v2/util/manifest.go b/internal/release/v2/util/manifest.go index 5dbcdaea5..d5698f468 100644 --- a/internal/release/v2/util/manifest.go +++ b/internal/release/v2/util/manifest.go @@ -34,7 +34,7 @@ type SimpleHead struct { } `json:"metadata,omitempty"` } -var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") +var sep = regexp.MustCompile(`(?m)^---[ \t]*`) // SplitManifests takes a manifest string and returns a map containing individual manifests. // diff --git a/internal/release/v2/util/manifest_test.go b/internal/release/v2/util/manifest_test.go index 463ab5a4d..1806368af 100644 --- a/internal/release/v2/util/manifest_test.go +++ b/internal/release/v2/util/manifest_test.go @@ -74,7 +74,7 @@ spec: name: "whitespace-only doc after separator is skipped", input: "---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1\n---\n \n", expected: map[string]string{ - "manifest-0": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1", + "manifest-0": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1\n", }, }, { @@ -110,7 +110,8 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -329,8 +330,8 @@ data: }, }, - // Multi-doc with block scalars: the regex consumes \s*\n before ---, - // so trailing newlines from non-last docs are stripped. + // Multi-doc with block scalars: the separator regex preserves trailing + // newlines from non-last documents. { name: "multi-doc block scalar clip (|) before separator", input: ` @@ -354,7 +355,8 @@ metadata: name: test data: key: | - hello`, + hello +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -387,7 +389,10 @@ metadata: name: test data: key: |+ - hello`, + hello + + +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -432,7 +437,8 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -460,11 +466,13 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: - name: cm2`, + name: cm2 +`, "manifest-2": `apiVersion: v1 kind: ConfigMap metadata: @@ -493,11 +501,13 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: - name: cm2`, + name: cm2 +`, "manifest-2": `apiVersion: v1 kind: ConfigMap metadata: diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 4ad08b761..ae59db4eb 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -1229,7 +1229,7 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: | hello --- apiVersion: v1 @@ -1269,7 +1269,7 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: | hello --- apiVersion: v1 @@ -1310,7 +1310,7 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: | hello --- apiVersion: v1 @@ -1473,7 +1473,7 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: | hello --- apiVersion: v1 @@ -1513,8 +1513,9 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: |+ hello + --- apiVersion: v1 kind: ConfigMap @@ -1554,8 +1555,10 @@ metadata: annotations: postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml' data: - key: |- + key: |+ hello + + --- apiVersion: v1 kind: ConfigMap diff --git a/pkg/action/testdata/rbac.txt b/pkg/action/testdata/rbac.txt index 91938d5cc..c8c2fd66e 100644 --- a/pkg/action/testdata/rbac.txt +++ b/pkg/action/testdata/rbac.txt @@ -8,6 +8,8 @@ rules: - apiGroups: [""] resources: ["pods", "pods/exec", "pods/log"] verbs: ["*"] + + --- # Source: hello/templates/rbac apiVersion: rbac.authorization.k8s.io/v1 diff --git a/pkg/cmd/testdata/output/object-order.txt b/pkg/cmd/testdata/output/object-order.txt index 1ff39f33c..96e3ba053 100644 --- a/pkg/cmd/testdata/output/object-order.txt +++ b/pkg/cmd/testdata/output/object-order.txt @@ -10,6 +10,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/01-a.yml # 2 @@ -22,6 +24,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/01-a.yml # 3 @@ -34,6 +38,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 5 @@ -46,6 +52,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 7 @@ -58,6 +66,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 8 @@ -70,6 +80,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 9 @@ -82,6 +94,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 10 @@ -94,6 +108,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 11 @@ -106,6 +122,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 12 @@ -118,6 +136,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 13 @@ -130,6 +150,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 14 @@ -142,6 +164,8 @@ spec: policyTypes: - Egress - Ingress + + --- # Source: object-order/templates/02-b.yml # 15 (11th object within 02-b.yml, in order to test `SplitManifests` which assigns `manifest-10` @@ -190,3 +214,5 @@ spec: policyTypes: - Egress - Ingress + + diff --git a/pkg/cmd/testdata/output/template-show-only-glob.txt b/pkg/cmd/testdata/output/template-show-only-glob.txt index b2d2b1c2d..160f08a06 100644 --- a/pkg/cmd/testdata/output/template-show-only-glob.txt +++ b/pkg/cmd/testdata/output/template-show-only-glob.txt @@ -8,6 +8,8 @@ rules: - apiGroups: [""] resources: ["pods"] verbs: ["get","list","watch"] + + --- # Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 @@ -22,3 +24,5 @@ subjects: - kind: ServiceAccount name: subchart-sa namespace: default + + diff --git a/pkg/cmd/testdata/output/template-show-only-multiple.txt b/pkg/cmd/testdata/output/template-show-only-multiple.txt index 1aac3081a..3f9aa6f2f 100644 --- a/pkg/cmd/testdata/output/template-show-only-multiple.txt +++ b/pkg/cmd/testdata/output/template-show-only-multiple.txt @@ -19,6 +19,7 @@ spec: name: nginx selector: app.kubernetes.io/name: subchart + --- # Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 @@ -36,3 +37,5 @@ spec: name: apache selector: app.kubernetes.io/name: subcharta + + diff --git a/pkg/cmd/testdata/output/template-show-only-one.txt b/pkg/cmd/testdata/output/template-show-only-one.txt index 9cc34f515..27a56c03c 100644 --- a/pkg/cmd/testdata/output/template-show-only-one.txt +++ b/pkg/cmd/testdata/output/template-show-only-one.txt @@ -19,3 +19,4 @@ spec: name: nginx selector: app.kubernetes.io/name: subchart + diff --git a/pkg/release/v1/util/manifest.go b/pkg/release/v1/util/manifest.go index fa26f6256..f76d006cd 100644 --- a/pkg/release/v1/util/manifest.go +++ b/pkg/release/v1/util/manifest.go @@ -34,7 +34,7 @@ type SimpleHead struct { } `json:"metadata,omitempty"` } -var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") +var sep = regexp.MustCompile(`(?m)^---[ \t]*`) // SplitManifests takes a manifest string and returns a map containing individual manifests. // diff --git a/pkg/release/v1/util/manifest_test.go b/pkg/release/v1/util/manifest_test.go index d1efa21e1..773723c86 100644 --- a/pkg/release/v1/util/manifest_test.go +++ b/pkg/release/v1/util/manifest_test.go @@ -74,7 +74,7 @@ spec: name: "whitespace-only doc after separator is skipped", input: "---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1\n---\n \n", expected: map[string]string{ - "manifest-0": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1", + "manifest-0": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm1\n", }, }, { @@ -110,7 +110,8 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -329,8 +330,8 @@ data: }, }, - // Multi-doc with block scalars: the regex consumes \s*\n before ---, - // so trailing newlines from non-last docs are stripped. + // Multi-doc with block scalars: the separator regex preserves trailing + // newlines from non-last documents. { name: "multi-doc block scalar clip (|) before separator", input: ` @@ -354,7 +355,8 @@ metadata: name: test data: key: | - hello`, + hello +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -387,7 +389,10 @@ metadata: name: test data: key: |+ - hello`, + hello + + +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -432,7 +437,8 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: @@ -460,11 +466,13 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: - name: cm2`, + name: cm2 +`, "manifest-2": `apiVersion: v1 kind: ConfigMap metadata: @@ -493,11 +501,13 @@ metadata: "manifest-0": `apiVersion: v1 kind: ConfigMap metadata: - name: cm1`, + name: cm1 +`, "manifest-1": `apiVersion: v1 kind: ConfigMap metadata: - name: cm2`, + name: cm2 +`, "manifest-2": `apiVersion: v1 kind: ConfigMap metadata: From 73c1fb245120df3f3adb53c12e69f29134147de7 Mon Sep 17 00:00:00 2001 From: Matheus Pimenta Date: Fri, 10 Jul 2026 22:34:56 +0100 Subject: [PATCH 061/161] Address review comments Signed-off-by: Matheus Pimenta --- pkg/action/action_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index ae59db4eb..880a9930b 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -1198,9 +1198,9 @@ data: `, }, - // Multi-doc tests: block scalar doc is NOT the last document. - // SplitManifests' regex consumes \s*\n before ---, so trailing - // newlines from non-last docs are always stripped. + // Multi-doc block scalar tests where the block scalar document is NOT the last: + // the separator regex does not consume trailing newlines, so YAML chomping + // indicators (|, |+, |-) are respected. // | (clip) in multi-doc (first doc) { From 84e63e5c38913594e476b15609fb6c7ab2d60467 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 08:08:39 -0600 Subject: [PATCH 062/161] chore(deps): bump oras.land/oras-go/v2 from 2.6.1 to 2.6.2 (#32333) Bumps [oras.land/oras-go/v2](https://github.com/oras-project/oras-go) from 2.6.1 to 2.6.2. - [Release notes](https://github.com/oras-project/oras-go/releases) - [Commits](https://github.com/oras-project/oras-go/compare/v2.6.1...v2.6.2) --- updated-dependencies: - dependency-name: oras.land/oras-go/v2 dependency-version: 2.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b3c6eb290..b2b3d6ca0 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( k8s.io/client-go v0.36.2 k8s.io/klog/v2 v2.140.0 k8s.io/kubectl v0.36.2 - oras.land/oras-go/v2 v2.6.1 + oras.land/oras-go/v2 v2.6.2 sigs.k8s.io/controller-runtime v0.24.1 sigs.k8s.io/kustomize/kyaml v0.21.1 sigs.k8s.io/yaml v1.6.0 diff --git a/go.sum b/go.sum index 06539321b..323cd5c1f 100644 --- a/go.sum +++ b/go.sum @@ -509,8 +509,8 @@ k8s.io/kubectl v0.36.2 h1:rpUGGpeL09XVOLep2yle5jrtk//JA1L6ZHfkQQtVEwk= k8s.io/kubectl v0.36.2/go.mod h1:gVbQ3B/yb4bSR2ggQ7rd0W6icUSWs7sduH4e16Vii+0= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -oras.land/oras-go/v2 v2.6.1 h1:bonOEkjLfp8tt6qXWRRWP6p1F+9octchOf2EqnWB4Zs= -oras.land/oras-go/v2 v2.6.1/go.mod h1:dhtFrFOuZuDtAVeZ9FUnaa5zfzplG3ZnFX9/uH1J/Yk= +oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo= +oras.land/oras-go/v2 v2.6.2/go.mod h1:PlTtg4JTDJkDe8yVHpM2wz7/YDc00GVas+i4jAW2TZ4= sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= From dad026acb8caab81411514715c50e50510f558ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 08:09:17 -0600 Subject: [PATCH 063/161] chore(deps): bump github.com/mattn/go-shellwords from 1.0.13 to 1.0.14 (#32334) Bumps [github.com/mattn/go-shellwords](https://github.com/mattn/go-shellwords) from 1.0.13 to 1.0.14. - [Commits](https://github.com/mattn/go-shellwords/compare/v1.0.13...v1.0.14) --- updated-dependencies: - dependency-name: github.com/mattn/go-shellwords dependency-version: 1.0.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b2b3d6ca0..016b0fded 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/gosuri/uitable v0.0.4 github.com/jmoiron/sqlx v1.4.0 github.com/lib/pq v1.12.3 - github.com/mattn/go-shellwords v1.0.13 + github.com/mattn/go-shellwords v1.0.14 github.com/moby/term v0.5.2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 diff --git a/go.sum b/go.sum index 323cd5c1f..d097bc72c 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.13 h1:DC0OMEpGjm6LfNFU4ckYcvbQKyp2vE8atyFGXNtDcf4= -github.com/mattn/go-shellwords v1.0.13/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-shellwords v1.0.14 h1:yUKzIgsCnosndOASY6/enly1EAuaXeFSQ7cdyA3OuYg= +github.com/mattn/go-shellwords v1.0.14/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= From fb53c00ae72c08cf6d64289efde3aaeeda6c42fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 08:09:20 -0600 Subject: [PATCH 064/161] chore(deps): bump actions/stale from 10.3.0 to 10.4.0 (#32330) Bumps [actions/stale](https://github.com/actions/stale) from 10.3.0 to 10.4.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899...1e223db275d687790206a7acac4d1a11bd6fe629) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 10.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index bbe339e79..678952b03 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -12,7 +12,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 + - uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' From b963afaddfe127620c70773e46b1d3a1f9c559e8 Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Sat, 11 Jul 2026 09:06:28 -0600 Subject: [PATCH 065/161] ci: track GitHub Actions updates on dev-v3 via Dependabot Dependabot reads its config only from the default branch, and the github-actions ecosystem was configured for main only. As a result, Action version bumps never flowed to dev-v3, leaving its workflows (e.g. govulncheck-action) frozen and drifting from main. Add a github-actions update block targeting dev-v3 so Action bumps are opened there too, matching the existing gomod/dev-v3 arrangement. Signed-off-by: Terry Howe --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0133fd8f4..d8e8e3379 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -37,3 +37,9 @@ updates: directory: "/" schedule: interval: "daily" + - # Keep dev-v3 GitHub Actions up to date, while Helm v3 is within support + package-ecosystem: "github-actions" + target-branch: "dev-v3" + directory: "/" + schedule: + interval: "daily" From 68977ec0b5a446286668170dd72bdf59695f8cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=80=E5=90=89?= <84045975+thc1006@users.noreply.github.com> Date: Sun, 12 Jul 2026 03:25:44 +0800 Subject: [PATCH 066/161] fix(ci): pin govulncheck-action to the v1.1.0 release (#32304) golang/govulncheck-action published v1.1.0 on 2026-07-10, tagging the master commit (032d455) the govulncheck step was already pinned to. Update the pin comment to # pin@v1.1.0 so it matches the repo's pin@ convention and Dependabot can track the action by semver again. The pinned SHA is unchanged; v1.1.0 points to that commit, so CI behavior is identical and only the trailing comment changes. Closes: #32301 Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --- .github/workflows/govulncheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 5e5111432..c7c9b3d53 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -30,6 +30,6 @@ jobs: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true - name: govulncheck - uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # pin@032d455 (from main 2026-07-06) + uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # pin@v1.1.0 with: go-package: ./... From d72b28ebcbecf1c582e57f17c1272536b90513d1 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 00:24:52 +0200 Subject: [PATCH 067/161] chore(internal): refactor: convert tests to testify assert/require part 1 refactor: convert tests to testify assert/require in internal/chart/v3/lint/rules Signed-off-by: Matthieu MOREL --- .../chart/v3/lint/rules/chartfile_test.go | 156 ++++----- .../chart/v3/lint/rules/deprecations_test.go | 25 +- internal/chart/v3/util/dependencies_test.go | 300 +++++------------- internal/plugin/metadata_test.go | 32 +- internal/plugin/verify_test.go | 113 +++---- 5 files changed, 200 insertions(+), 426 deletions(-) diff --git a/internal/chart/v3/lint/rules/chartfile_test.go b/internal/chart/v3/lint/rules/chartfile_test.go index a7669a0aa..9ac4ce75e 100644 --- a/internal/chart/v3/lint/rules/chartfile_test.go +++ b/internal/chart/v3/lint/rules/chartfile_test.go @@ -18,11 +18,15 @@ package rules import ( "errors" + "fmt" "os" "path/filepath" - "strings" + "strconv" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/lint/support" chartutil "helm.sh/helm/v4/internal/chart/v3/util" @@ -49,33 +53,23 @@ func TestValidateChartYamlNotDirectory(t *testing.T) { defer os.Remove(nonExistingChartFilePath) err := validateChartYamlNotDirectory(nonExistingChartFilePath) - if err == nil { - t.Error("validateChartYamlNotDirectory to return a linter error, got no error") - } + assert.Error(t, err, "validateChartYamlNotDirectory to return a linter error, got no error") } func TestValidateChartYamlFormat(t *testing.T) { err := validateChartYamlFormat(errors.New("Read error")) - if err == nil { - t.Error("validateChartYamlFormat to return a linter error, got no error") - } + require.Error(t, err, "validateChartYamlFormat to return a linter error, got no error") err = validateChartYamlFormat(nil) - if err != nil { - t.Error("validateChartYamlFormat to return no error, got a linter error") - } + assert.NoError(t, err, "validateChartYamlFormat to return no error, got a linter error") } func TestValidateChartName(t *testing.T) { err := validateChartName(badChart) - if err == nil { - t.Error("validateChartName to return a linter error, got no error") - } + require.Error(t, err, "validateChartName to return a linter error, got no error") err = validateChartName(badChartName) - if err == nil { - t.Error("expected validateChartName to return a linter error for an invalid name, got no error") - } + assert.Error(t, err, "expected validateChartName to return a linter error for an invalid name, got no error") } func TestValidateChartVersion(t *testing.T) { @@ -93,20 +87,18 @@ func TestValidateChartVersion(t *testing.T) { var successTest = []string{"0.0.1", "0.0.1+build", "0.0.1-beta"} - for _, test := range failTest { - badChart.Version = test.Version - err := validateChartVersion(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) - } + for i, test := range failTest { + t.Run(strconv.Itoa(i), func(t *testing.T) { + badChart.Version = test.Version + err := validateChartVersion(badChart) + require.ErrorContains(t, err, test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) + }) } for _, version := range successTest { badChart.Version = version err := validateChartVersion(badChart) - if err != nil { - t.Errorf("validateChartVersion(%s) to return no error, got a linter error", version) - } + assert.NoError(t, err, "validateChartVersion(%s) to return no error, got a linter error", version) } } @@ -130,49 +122,43 @@ func TestValidateChartMaintainer(t *testing.T) { } for _, test := range failTest { - badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) - } + t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { + badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} + err := validateChartMaintainer(badChart) + require.ErrorContains(t, err, test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) + }) } for _, test := range successTest { - badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err != nil { - t.Errorf("validateChartMaintainer(%s, %s) to return no error, got %s", test.Name, test.Email, err.Error()) - } + t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { + badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} + err := validateChartMaintainer(badChart) + require.NoError(t, err, "validateChartMaintainer(%s, %s) to return no error", test.Name, test.Email) + }) } // Testing for an empty maintainer badChart.Maintainers = []*chart.Maintainer{nil} err := validateChartMaintainer(badChart) - if err == nil { - t.Error("validateChartMaintainer did not return error for nil maintainer as expected") - } - if err.Error() != "a maintainer entry is empty" { - t.Errorf("validateChartMaintainer returned unexpected error for nil maintainer: %s", err.Error()) - } + require.Error(t, err, "validateChartMaintainer did not return error for nil maintainer as expected") + assert.EqualError(t, err, "a maintainer entry is empty", "validateChartMaintainer returned unexpected error for nil maintainer") } func TestValidateChartSources(t *testing.T) { var failTest = []string{"", "RiverRun", "john@winterfell", "riverrun.io"} var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} for _, test := range failTest { - badChart.Sources = []string{test} - err := validateChartSources(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid source URL") { - t.Errorf("validateChartSources(%s) to return \"invalid source URL\", got no error", test) - } + t.Run(test, func(t *testing.T) { + badChart.Sources = []string{test} + err := validateChartSources(badChart) + require.ErrorContains(t, err, "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) + }) } for _, test := range successTest { badChart.Sources = []string{test} err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartSources(%s) to return no error, got %s", test, err.Error()) - } + assert.NoError(t, err, "validateChartSources(%s) to return no error", test) } } @@ -184,11 +170,8 @@ func TestValidateChartIconPresence(t *testing.T) { err := validateChartIconPresence(testChart) - if err == nil { - t.Error("validateChartIconPresence to return a linter error, got no error") - } else if !strings.Contains(err.Error(), "icon is recommended") { - t.Errorf("expected %q, got %q", "icon is recommended", err.Error()) - } + require.Error(t, err, "validateChartIconPresence to return a linter error, got no error") + assert.ErrorContains(t, err, "icon is recommended", "expected %q", "icon is recommended") }) t.Run("Icon present", func(t *testing.T) { testChart := &chart.Metadata{ @@ -197,9 +180,7 @@ func TestValidateChartIconPresence(t *testing.T) { err := validateChartIconPresence(testChart) - if err != nil { - t.Errorf("Unexpected error: %q", err.Error()) - } + assert.NoError(t, err, "Unexpected error") }) } @@ -207,19 +188,17 @@ func TestValidateChartIconURL(t *testing.T) { var failTest = []string{"RiverRun", "john@winterfell", "riverrun.io"} var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} for _, test := range failTest { - badChart.Icon = test - err := validateChartIconURL(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid icon URL") { - t.Errorf("validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) - } + t.Run(test, func(t *testing.T) { + badChart.Icon = test + err := validateChartIconURL(badChart) + require.ErrorContains(t, err, "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) + }) } for _, test := range successTest { badChart.Icon = test - err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartIconURL(%s) to return no error, got %s", test, err.Error()) - } + err := validateChartIconURL(badChart) + assert.NoError(t, err, "validateChartIconURL(%s) to return no error", test) } } @@ -230,26 +209,11 @@ func TestV3Chartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 6 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - - if !strings.Contains(msgs[0].Err.Error(), "name is required") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be \"v3\"") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } - - if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } + require.Lenf(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors", expectedNumberOfErrorMessages) + require.ErrorContains(t, msgs[0].Err, "name is required", "Unexpected message 0") + require.ErrorContains(t, msgs[1].Err, "apiVersion is required. The value must be \"v3\"", "Unexpected message 1") + require.ErrorContains(t, msgs[2].Err, "version '0.0.0.0' is not a valid SemVer", "Unexpected message 2") + assert.ErrorContains(t, msgs[3].Err, "icon is recommended", "Unexpected message 3") }) t.Run("Chart.yaml validity issues due to type mismatch", func(t *testing.T) { @@ -258,21 +222,9 @@ func TestV3Chartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 3 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - - if !strings.Contains(msgs[0].Err.Error(), "version should be of type string") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "version '7.2445e+06' is not a valid SemVer") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "appVersion should be of type string") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } + require.Lenf(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors", expectedNumberOfErrorMessages) + require.ErrorContains(t, msgs[0].Err, "version should be of type string", "Unexpected message 0") + require.ErrorContains(t, msgs[1].Err, "version '7.2445e+06' is not a valid SemVer", "Unexpected message 1") + assert.ErrorContains(t, msgs[2].Err, "appVersion should be of type string", "Unexpected message 2") }) } diff --git a/internal/chart/v3/lint/rules/deprecations_test.go b/internal/chart/v3/lint/rules/deprecations_test.go index 2b12a88f9..a255abf50 100644 --- a/internal/chart/v3/lint/rules/deprecations_test.go +++ b/internal/chart/v3/lint/rules/deprecations_test.go @@ -16,7 +16,12 @@ limitations under the License. package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) func TestValidateNoDeprecations(t *testing.T) { deprecated := &k8sYamlStruct{ @@ -24,18 +29,14 @@ func TestValidateNoDeprecations(t *testing.T) { Kind: "Deployment", } err := validateNoDeprecations(deprecated, nil) - if err == nil { - t.Fatal("Expected deprecated extension to be flagged") - } - depErr := err.(deprecatedAPIError) - if depErr.Message == "" { - t.Fatalf("Expected error message to be non-blank: %v", err) - } + var depErr deprecatedAPIError + require.Error(t, err, "Expected deprecated extension to be flagged") + require.ErrorAs(t, err, &depErr, "Expected error to be of type deprecatedAPIError") + require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank: %v", err) - if err := validateNoDeprecations(&k8sYamlStruct{ + err = validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", - }, nil); err != nil { - t.Error("Expected a v1 Pod to not be deprecated") - } + }, nil) + assert.NoError(t, err, "Expected a v1 Pod to not be deprecated") } diff --git a/internal/chart/v3/util/dependencies_test.go b/internal/chart/v3/util/dependencies_test.go index 0a0937e4a..f6ca06da3 100644 --- a/internal/chart/v3/util/dependencies_test.go +++ b/internal/chart/v3/util/dependencies_test.go @@ -21,6 +21,9 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/loader" "helm.sh/helm/v4/pkg/chart/common" @@ -29,9 +32,7 @@ import ( func loadChart(t *testing.T, path string) *chart.Chart { t.Helper() c, err := loader.Load(path) - if err != nil { - t.Fatalf("failed to load testdata: %s", err) - } + require.NoError(t, err, "failed to load testdata") return c } @@ -42,19 +43,11 @@ func TestLoadDependency(t *testing.T) { } check := func(deps []*chart.Dependency) { - if len(deps) != 2 { - t.Errorf("expected 2 dependencies, got %d", len(deps)) - } + require.Len(t, deps, 2, "expected 2 dependencies") for i, tt := range tests { - if deps[i].Name != tt.Name { - t.Errorf("expected dependency named %q, got %q", tt.Name, deps[i].Name) - } - if deps[i].Version != tt.Version { - t.Errorf("expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) - } - if deps[i].Repository != tt.Repository { - t.Errorf("expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) - } + assert.Equal(t, tt.Name, deps[i].Name, "expected dependency named %q, got %q", tt.Name, deps[i].Name) + assert.Equal(t, tt.Version, deps[i].Version, "expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) + assert.Equal(t, tt.Repository, deps[i].Repository, "expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) } } c := loadChart(t, "testdata/frobnitz") @@ -117,18 +110,12 @@ func TestDependencyEnabled(t *testing.T) { for _, tc := range tests { c := loadChart(t, "testdata/subpop") t.Run(tc.name, func(t *testing.T) { - if err := processDependencyEnabled(c, tc.v, ""); err != nil { - t.Fatalf("error processing enabled dependencies %v", err) - } + require.NoErrorf(t, processDependencyEnabled(c, tc.v, ""), "error processing enabled dependencies") names := extractChartNames(c) - if len(names) != len(tc.e) { - t.Fatalf("slice lengths do not match got %v, expected %v", len(names), len(tc.e)) - } + require.Len(t, names, len(tc.e), "slice lengths do not match got %v, expected %v", len(names), len(tc.e)) for i := range names { - if names[i] != tc.e[i] { - t.Fatalf("slice values do not match got %v, expected %v", names, tc.e) - } + require.Equal(t, tc.e[i], names[i], "slice values do not match got %v, expected %v", names, tc.e) } }) } @@ -219,68 +206,44 @@ func TestProcessDependencyImportValues(t *testing.T) { e["SCBexported2A"] = "blaster" e["global.SC1exported2.all.SC1exported3"] = "SC1expstr" - if err := processDependencyImportValues(c, false); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoError(t, processDependencyImportValues(c, false), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v for key %q", s, vv, kk) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, vv, s, "failed to match imported float value %v with expected %v for key %q", s, vv, kk) case bool: - if b := strconv.FormatBool(pv); b != vv { - t.Errorf("failed to match imported bool value %v with expected %v for key %q", b, vv, kk) - } + b := strconv.FormatBool(pv) + assert.Equalf(t, vv, b, "failed to match imported bool value %v with expected %v for key %q", b, vv, kk) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q for key %q", pv, vv, kk) - } + assert.Equalf(t, vv, pv, "failed to match imported string value %q with expected %q for key %q", pv, vv, kk) } } // Since this was processed with coalescing there should be no null values. // Here we verify that. _, err := cc.PathValue("ensurenull") - if err == nil { - t.Error("expect nil value not found but found it") - } - switch xerr := err.(type) { - case common.ErrNoValue: - // We found what we expected - default: - t.Errorf("expected an ErrNoValue but got %q instead", xerr) - } + require.Error(t, err, "expect nil value not found but found it") + var xerr common.ErrNoValue + require.ErrorAs(t, err, &xerr, "expected an ErrNoValue") c = loadChart(t, "testdata/subpop") - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoError(t, processDependencyImportValues(c, true), "processing import values dependencies") cc = common.Values(c.Values) val, err := cc.PathValue("ensurenull") - if err != nil { - t.Error("expect value but ensurenull was not found") - } - if val != nil { - t.Errorf("expect nil value but got %q instead", val) - } + require.NoError(t, err, "expect value but ensurenull was not found") + assert.Nil(t, val, "expect nil value but got %v instead", val) } func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T) { c := loadChart(t, "testdata/chart-with-import-from-aliased-dependencies") - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.NoError(t, processDependencyImportValues(c, true), "processing import values dependencies") e := make(map[string]string) e["foo-defaults.defaultValue"] = "42" @@ -295,12 +258,8 @@ func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T cValues := common.Values(c.Values) for kk, vv := range e { pv, err := cValues.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } - if pv != vv { - t.Errorf("failed to match imported value %v with expected %v", pv, vv) - } + require.NoError(t, err, "retrieving import values table %v", kk) + assert.Equal(t, vv, pv, "failed to match imported value %v with expected %v", pv, vv) } } @@ -327,25 +286,18 @@ func TestProcessDependencyImportValuesMultiLevelPrecedence(t *testing.T) { e["app2.service.port"] = "8080" e["app3.service.port"] = "9090" e["app4.service.port"] = "1234" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoError(t, processDependencyImportValues(c, true), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v", s, vv) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, vv, s, "failed to match imported float value %v with expected %v", s, vv) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q", pv, vv) - } + assert.Equalf(t, vv, pv, "failed to match imported string value %q with expected %q", pv, vv) } } } @@ -354,127 +306,72 @@ func TestProcessDependencyImportValuesForEnabledCharts(t *testing.T) { c := loadChart(t, "testdata/import-values-from-enabled-subchart/parent-chart") nameOverride := "parent-chart-prod" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 1 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } + require.NoError(t, processDependencyImportValues(c, true), "processing import values dependencies") + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 1, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) prodDependencyValues := c.Dependencies()[0].Values - if prodDependencyValues["nameOverride"] != nameOverride { - t.Fatalf("dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) - } + require.Equal(t, nameOverride, prodDependencyValues["nameOverride"], "dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) } func TestGetAliasDependency(t *testing.T) { c := loadChart(t, "testdata/frobnitz") req := c.Metadata.Dependencies - if len(req) == 0 { - t.Fatal("there are no dependencies to test") - } + require.NotEmpty(t, req, "there are no dependencies to test") // Success case aliasChart := getAliasDependency(c.Dependencies(), req[0]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[0].Name) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[0].Name) if req[0].Alias != "" { - if aliasChart.Name() != req[0].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[0].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) + require.Equal(t, req[0].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) + } else { + require.Equal(t, req[0].Name, aliasChart.Name(), "dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) } - if req[0].Version != "" { - if !IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version is not in the compatible range") - } + require.True(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version is not in the compatible range") } // Failure case req[0].Name = "something-else" - if aliasChart := getAliasDependency(c.Dependencies(), req[0]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nil(t, getAliasDependency(c.Dependencies(), req[0]), "expected no chart") req[0].Version = "something else which is not in the compatible range" - if IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version outside the compatible range should not be considered compatible") - } + require.False(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version outside the compatible range should not be considered compatible") } func TestDependentChartAliases(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-alias") req := c.Metadata.Dependencies - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 3 { - t.Fatal("expected alias dependencies to be added") - } - - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 3, "expected alias dependencies to be added") + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) aliasChart := getAliasDependency(c.Dependencies(), req[2]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[2].Name) - } - if aliasChart.Parent() != c { - t.Fatalf("dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[2].Name) + require.Equal(t, c, aliasChart.Parent(), "dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) if req[2].Alias != "" { - if aliasChart.Name() != req[2].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[2].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) + require.Equal(t, req[2].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) + } else { + require.Equal(t, req[2].Name, aliasChart.Name(), "dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) } - req[2].Name = "dummy-name" - if aliasChart := getAliasDependency(c.Dependencies(), req[2]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nil(t, getAliasDependency(c.Dependencies(), req[2]), "expected no chart") } func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-no-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } + err := processDependencyEnabled(c, c.Values, "") + require.NoError(t, err, "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") } func TestDependentChartWithSubChartsHelmignore(t *testing.T) { @@ -484,86 +381,53 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { func TestDependentChartsWithSubChartsSymlink(t *testing.T) { joonix := filepath.Join("testdata", "joonix") - if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { - t.Fatal(err) - } + err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")) + require.NoError(t, err, "failed to create symlink") defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) c := loadChart(t, joonix) - if c.Name() != "joonix" { - t.Fatalf("unexpected chart name: %s", c.Name()) - } - if n := len(c.Dependencies()); n != 1 { - t.Fatalf("expected 1 dependency for this chart, but got %d", n) - } + require.Equal(t, "joonix", c.Name(), "unexpected chart name: %s", c.Name()) + require.Len(t, c.Dependencies(), 1, "expected 1 dependency for this chart") } func TestDependentChartsWithSubchartsAllSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-all-in-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } + err := processDependencyEnabled(c, c.Values, "") + require.NoError(t, err, "expected no errors") - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) } func TestDependentChartsWithSomeSubchartsSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-mixed-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) } func validateDependencyTree(t *testing.T, c *chart.Chart) { t.Helper() for _, dependency := range c.Dependencies() { - if dependency.Parent() != c { - if dependency.Parent() != c { - t.Fatalf("dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) - } - } - // recurse entire tree - validateDependencyTree(t, dependency) + t.Run(dependency.Name(), func(t *testing.T) { + require.Equal(t, c, dependency.Parent(), "dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) + // recurse entire tree + validateDependencyTree(t, dependency) + }) } } func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *testing.T) { c := loadChart(t, "testdata/chart-with-dependency-aliased-twice") - if len(c.Dependencies()) != 1 { - t.Fatalf("expected one dependency for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected two dependencies after processing aliases") - } + require.Len(t, c.Dependencies(), 1, "expected one dependency for this chart, but got %d", len(c.Dependencies())) + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected two dependencies after processing aliases") validateDependencyTree(t, c) } diff --git a/internal/plugin/metadata_test.go b/internal/plugin/metadata_test.go index 6113f30c7..b4994cf68 100644 --- a/internal/plugin/metadata_test.go +++ b/internal/plugin/metadata_test.go @@ -16,10 +16,12 @@ limitations under the License. package plugin import ( + "strconv" "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestValidatePluginData(t *testing.T) { @@ -61,15 +63,15 @@ func TestValidatePluginData(t *testing.T) { {true, mockNoCommand, ""}, // Test no command metadata works {true, mockLegacyCommand, ""}, // Test legacy command metadata works } { - err := item.plug.Metadata().Validate() - if item.pass && err != nil { - t.Errorf("failed to validate case %d: %s", i, err) - } else if !item.pass && err == nil { - t.Errorf("expected case %d to fail", i) - } - if !item.pass && !strings.Contains(err.Error(), item.errString) { - t.Errorf("index [%d]: expected error to contain: %s, but got: %s", i, item.errString, err.Error()) - } + t.Run(strconv.Itoa(i), func(t *testing.T) { + err := item.plug.Metadata().Validate() + if item.pass { + require.NoError(t, err, "failed to validate case %d: %s", i, err) + } else { + require.Error(t, err, "expected case %d to fail", i) + assert.ErrorContains(t, err, item.errString, "expected case %d error to contain %q", i, item.errString) + } + }) } } @@ -122,9 +124,7 @@ func TestMetadataValidateMultipleErrors(t *testing.T) { } err := metadata.Validate() - if err == nil { - t.Fatal("expected validation to fail with multiple errors") - } + require.Error(t, err, "expected validation to fail with multiple errors") errStr := err.Error() @@ -139,9 +139,7 @@ func TestMetadataValidateMultipleErrors(t *testing.T) { } for _, expectedErr := range expectedErrors { - if !strings.Contains(errStr, expectedErr) { - t.Errorf("expected error to contain %q, but got: %v", expectedErr, errStr) - } + assert.Contains(t, errStr, expectedErr, "expected error to contain %q, but got: %v", expectedErr, errStr) } // Verify that the error contains the correct number of error messages @@ -152,7 +150,5 @@ func TestMetadataValidateMultipleErrors(t *testing.T) { } } - if errorCount < len(expectedErrors) { - t.Errorf("expected %d errors, but only found %d in: %v", len(expectedErrors), errorCount, errStr) - } + assert.GreaterOrEqual(t, errorCount, len(expectedErrors), "expected %d errors, but only found %d in: %v", len(expectedErrors), errorCount, errStr) } diff --git a/internal/plugin/verify_test.go b/internal/plugin/verify_test.go index 2828d30b6..5721e0414 100644 --- a/internal/plugin/verify_test.go +++ b/internal/plugin/verify_test.go @@ -20,6 +20,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/provenance" ) @@ -41,20 +44,16 @@ func TestVerifyPlugin(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(tempDir, "verify-test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + err := os.MkdirAll(pluginDir, 0o755) + require.NoError(t, err) - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) + require.NoError(t, err) // Create tarball tarballPath := filepath.Join(tempDir, "verify-test-plugin.tar.gz") tarFile, err := os.Create(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if err := CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { tarFile.Close() @@ -64,61 +63,41 @@ func TestVerifyPlugin(t *testing.T) { // Sign the plugin with source directory signer, err := provenance.NewFromKeyring(testKeyFile, "helm-test") - if err != nil { - t.Fatal(err) - } - if err := signer.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, err) + err = signer.DecryptKey(func(_ string) ([]byte, error) { return []byte(""), nil - }); err != nil { - t.Fatal(err) - } + }) + require.NoError(t, err) // Read the tarball data tarballData, err := os.ReadFile(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := SignPlugin(tarballData, filepath.Base(tarballPath), signer) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Write the signature to .prov file provFile := tarballPath + ".prov" - if err := os.WriteFile(provFile, []byte(sig), 0o644); err != nil { - t.Fatal(err) - } + err = os.WriteFile(provFile, []byte(sig), 0o644) + require.NoError(t, err) // Read the files for verification archiveData, err := os.ReadFile(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) provData, err := os.ReadFile(provFile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Now verify the plugin verification, err := VerifyPlugin(archiveData, provData, filepath.Base(tarballPath), testPubFile) - if err != nil { - t.Fatalf("Failed to verify plugin: %v", err) - } + require.NoError(t, err, "Failed to verify plugin") // Check verification results - if verification.SignedBy == nil { - t.Error("SignedBy is nil") - } + assert.NotNil(t, verification.SignedBy, "SignedBy is nil") - if verification.FileName != "verify-test-plugin.tar.gz" { - t.Errorf("Expected filename 'verify-test-plugin.tar.gz', got %s", verification.FileName) - } + assert.Equal(t, "verify-test-plugin.tar.gz", verification.FileName, "Expected filename 'verify-test-plugin.tar.gz', got %s", verification.FileName) - if verification.FileHash == "" { - t.Error("FileHash is empty") - } + assert.NotEmpty(t, verification.FileHash, "FileHash is empty") } func TestVerifyPluginBadSignature(t *testing.T) { @@ -126,19 +105,15 @@ func TestVerifyPluginBadSignature(t *testing.T) { // Create a plugin tarball pluginDir := filepath.Join(tempDir, "bad-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + err := os.MkdirAll(pluginDir, 0o755) + require.NoError(t, err) - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) + require.NoError(t, err) tarballPath := filepath.Join(tempDir, "bad-plugin.tar.gz") tarFile, err := os.Create(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if err := CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { tarFile.Close() @@ -158,26 +133,19 @@ InvalidSignatureData -----END PGP SIGNATURE-----` provFile := tarballPath + ".prov" - if err := os.WriteFile(provFile, []byte(badSig), 0o644); err != nil { - t.Fatal(err) - } + err = os.WriteFile(provFile, []byte(badSig), 0o644) + require.NoError(t, err) // Read the files archiveData, err := os.ReadFile(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) provData, err := os.ReadFile(provFile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Try to verify - should fail _, err = VerifyPlugin(archiveData, provData, filepath.Base(tarballPath), testPubFile) - if err == nil { - t.Error("Expected verification to fail with bad signature") - } + assert.Error(t, err, "Expected verification to fail with bad signature") } func TestVerifyPluginMissingProvenance(t *testing.T) { @@ -185,21 +153,16 @@ func TestVerifyPluginMissingProvenance(t *testing.T) { tarballPath := filepath.Join(tempDir, "no-prov.tar.gz") // Create a minimal tarball - if err := os.WriteFile(tarballPath, []byte("dummy"), 0o644); err != nil { - t.Fatal(err) - } + err := os.WriteFile(tarballPath, []byte("dummy"), 0o644) + require.NoError(t, err) // Read the tarball data archiveData, err := os.ReadFile(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Try to verify with empty provenance data _, err = VerifyPlugin(archiveData, nil, filepath.Base(tarballPath), testPubFile) - if err == nil { - t.Error("Expected verification to fail with empty provenance data") - } + assert.Error(t, err, "Expected verification to fail with empty provenance data") } func TestVerifyPluginMalformedData(t *testing.T) { @@ -208,7 +171,5 @@ func TestVerifyPluginMalformedData(t *testing.T) { provData := []byte("fake provenance") _, err := VerifyPlugin(malformedData, provData, "malformed.tar.gz", testPubFile) - if err == nil { - t.Error("Expected malformed data verification to fail, but it succeeded") - } + assert.Error(t, err, "Expected malformed data verification to fail, but it succeeded") } From f280d9c1b5da4e2f25cac76b2fcce58bad35aae9 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 00:24:50 +0200 Subject: [PATCH 068/161] chore(internal): refactor: convert tests to testify assert/require part 2 refactor: convert tests to testify assert/require in internal/chart/v3/util Signed-off-by: Matthieu MOREL --- internal/chart/v3/lint/lint_test.go | 43 +++------- internal/chart/v3/lint/rules/template_test.go | 85 +++++++----------- internal/chart/v3/util/chartfile_test.go | 59 ++++--------- internal/chart/v3/util/create_test.go | 39 +++------ internal/chart/v3/util/expand_test.go | 56 +++--------- internal/chart/v3/util/save_test.go | 86 ++++++------------- internal/plugin/subprocess_commands_test.go | 71 +++++---------- 7 files changed, 129 insertions(+), 310 deletions(-) diff --git a/internal/chart/v3/lint/lint_test.go b/internal/chart/v3/lint/lint_test.go index 6a2558fe0..8916c6e22 100644 --- a/internal/chart/v3/lint/lint_test.go +++ b/internal/chart/v3/lint/lint_test.go @@ -92,35 +92,23 @@ func TestBadChartV3(t *testing.T) { func TestInvalidYaml(t *testing.T) { var values map[string]any m := RunAll(badYamlFileDir, values, namespace).Messages - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "deliberateSyntaxError") { - t.Error("All didn't have the error for deliberateSyntaxError") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "deliberateSyntaxError", "All didn't have the error for deliberateSyntaxError") } func TestInvalidChartYamlV3(t *testing.T) { var values map[string]any m := RunAll(invalidChartFileDir, values, namespace).Messages t.Log(m) - if len(m) != 3 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "failed to strictly parse chart metadata file") { - t.Error("All didn't have the error for duplicate YAML keys") - } + require.Len(t, m, 3, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "failed to strictly parse chart metadata file", "All didn't have the error for duplicate YAML keys") } func TestBadValuesV3(t *testing.T) { var values map[string]any m := RunAll(badValuesFileDir, values, namespace).Messages - if len(m) < 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "unable to parse YAML") { - t.Errorf("All didn't have the error for invalid key format: %s", m[0].Err) - } + require.NotEmptyf(t, m, "All didn't fail with expected errors") + assert.ErrorContains(t, m[0].Err, "unable to parse YAML", "All didn't have the error for invalid key format: %s", m[0].Err) } func TestBadCrdFileV3(t *testing.T) { @@ -150,11 +138,7 @@ func TestHelmCreateChart(t *testing.T) { dir := t.TempDir() createdChart, err := chartutil.Create("testhelmcreatepasseslint", dir) - if err != nil { - t.Error(err) - // Fatal is bad because of the defer. - return - } + require.NoError(t, err) // Note: we test with strict=true here, even though others have // strict = false. @@ -178,10 +162,7 @@ func TestHelmCreateChart(t *testing.T) { // of the `--set` flag. func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { createdChart, err := chartutil.Create("checkdeprecatedwarnings", t.TempDir()) - if err != nil { - t.Error(err) - return - } + require.NoError(t, err) // Add values to enable hpa, and ingress which are disabled by default. // This is the equivalent of: @@ -234,11 +215,7 @@ func TestMalformedTemplate(t *testing.T) { case <-c: t.Fatal("lint malformed template timeout") case <-ch: - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "invalid character '{'") { - t.Error("All didn't have the error for invalid character '{'") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "invalid character '{'", "All didn't have the error for invalid character '{'") } } diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index 88343b330..0b83e1cd5 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -20,10 +20,12 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/lint/support" chartutil "helm.sh/helm/v4/internal/chart/v3/util" @@ -36,16 +38,12 @@ func TestValidateAllowedExtension(t *testing.T) { var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { err := validateAllowedExtension(test) - if err == nil || !strings.Contains(err.Error(), "Valid extensions are .yaml, .yml, .tpl, or .txt") { - t.Errorf("validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) - } + require.ErrorContains(t, err, "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { err := validateAllowedExtension(test) - if err != nil { - t.Errorf("validateAllowedExtension('%s') to return no error but got \"%s\"", test, err.Error()) - } + assert.NoError(t, err, "validateAllowedExtension('%s') to return no error", test) } } @@ -59,13 +57,9 @@ func TestTemplateParsing(t *testing.T) { Templates(&linter, values, namespace, strict) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected one error, got %d, %v", len(res), res) - } + require.Len(t, res, 1, "Expected one error, got %d, %v", len(res), res) - if !strings.Contains(res[0].Err.Error(), "deliberateSyntaxError") { - t.Errorf("Unexpected error: %s", res[0]) - } + assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError", "Unexpected error: %s", res[0]) } var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") @@ -82,9 +76,7 @@ func TestTemplateIntegrationHappyPath(t *testing.T) { Templates(&linter, values, namespace, strict) res := linter.Messages - if len(res) != 0 { - t.Fatalf("Expected no error, got %d, %v", len(res), res) - } + require.Empty(t, res, "Expected no error, got %d, %v", len(res), res) } func TestMultiTemplateFail(t *testing.T) { @@ -92,13 +84,9 @@ func TestMultiTemplateFail(t *testing.T) { Templates(&linter, values, namespace, strict) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected 1 error, got %d, %v", len(res), res) - } + require.Len(t, res, 1, "Expected 1 error, got %d, %v", len(res), res) - if !strings.Contains(res[0].Err.Error(), "object name does not conform to Kubernetes naming requirements") { - t.Errorf("Unexpected error: %s", res[0].Err) - } + assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements", "Unexpected error: %s", res[0].Err) } func TestValidateMetadataName(t *testing.T) { @@ -176,8 +164,11 @@ func TestValidateMetadataName(t *testing.T) { } for _, tt := range tests { t.Run(fmt.Sprintf("%s/%s", tt.obj.Kind, tt.obj.Metadata.Name), func(t *testing.T) { - if err := validateMetadataName(tt.obj); (err != nil) != tt.wantErr { - t.Errorf("validateMetadataName() error = %v, wantErr %v", err, tt.wantErr) + err := validateMetadataName(tt.obj) + if tt.wantErr { + require.Error(t, err, "validateMetadataName()") + } else { + require.NoError(t, err, "validateMetadataName()") } }) } @@ -207,9 +198,7 @@ func TestDeprecatedAPIFails(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) @@ -220,10 +209,9 @@ func TestDeprecatedAPIFails(t *testing.T) { t.Fatalf("Expected 1 lint error, got %d", l) } - err := linter.Messages[0].Err.(deprecatedAPIError) - if err.Deprecated != "apps/v1beta1 Deployment" { - t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) - } + var err deprecatedAPIError + require.ErrorAs(t, linter.Messages[0].Err, &err, "Expected error to be of type deprecatedAPIError") + assert.Equal(t, "apps/v1beta1 Deployment", err.Deprecated, "Surprised to learn that %q is deprecated", err.Deprecated) } const manifest = `apiVersion: v1 @@ -262,9 +250,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { }, } dir := t.TempDir() - if err := chartutil.SaveDir(&ch, dir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&ch, dir)) linter := &support.Linter{ ChartDir: filepath.Join(dir, ch.Metadata.Name), } @@ -306,9 +292,8 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + err := validateMatchSelector(md, manifest) + require.NoError(t, err) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -330,9 +315,8 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + err = validateMatchSelector(md, manifest) + require.NoError(t, err) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -351,9 +335,8 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err == nil { - t.Error("expected Deployment with no selector to fail") - } + err = validateMatchSelector(md, manifest) + assert.Error(t, err, "expected Deployment with no selector to fail") } func TestValidateTopIndentLevel(t *testing.T) { @@ -392,9 +375,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) @@ -424,9 +405,7 @@ items: helm.sh/resource-policy: keep ` - if err := validateListAnnotations(md, manifest); err == nil { - t.Fatal("expected list with nested keep annotations to fail") - } + require.Error(t, validateListAnnotations(md, manifest), "expected list with nested keep annotations to fail") manifest = ` apiVersion: v1 @@ -439,9 +418,7 @@ items: kind: ConfigMap ` - if err := validateListAnnotations(md, manifest); err != nil { - t.Fatalf("List objects keep annotations should pass. got: %s", err) - } + require.NoError(t, validateListAnnotations(md, manifest), "List objects keep annotations should pass") } func TestIsYamlFileExtension(t *testing.T) { @@ -457,8 +434,6 @@ func TestIsYamlFileExtension(t *testing.T) { for _, test := range tests { result := isYamlFileExtension(test.filename) - if result != test.expected { - t.Errorf("isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) - } + assert.Equal(t, test.expected, result, "isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) } } diff --git a/internal/chart/v3/util/chartfile_test.go b/internal/chart/v3/util/chartfile_test.go index 65cb27923..c791930c1 100644 --- a/internal/chart/v3/util/chartfile_test.go +++ b/internal/chart/v3/util/chartfile_test.go @@ -19,6 +19,9 @@ package util import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" ) @@ -35,57 +38,31 @@ func TestLoadChartfile(t *testing.T) { func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { t.Helper() - if f == nil { - t.Fatal("Failed verifyChartfile because f is nil") - } + require.NotNil(t, f, "Failed verifyChartfile because f is nil") - if f.Name != name { - t.Errorf("Expected %s, got %s", name, f.Name) - } + assert.Equal(t, name, f.Name, "Expected %s, got %s", name, f.Name) - if f.Description != "This is a frobnitz." { - t.Errorf("Unexpected description %q", f.Description) - } + assert.Equal(t, "This is a frobnitz.", f.Description, "Unexpected description %q", f.Description) - if f.Version != "1.2.3" { - t.Errorf("Unexpected version %q", f.Version) - } + assert.Equal(t, "1.2.3", f.Version, "Unexpected version %q", f.Version) - if len(f.Maintainers) != 2 { - t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers)) - } + assert.Len(t, f.Maintainers, 2, "Expected 2 maintainers, got %d", len(f.Maintainers)) - if f.Maintainers[0].Name != "The Helm Team" { - t.Error("Unexpected maintainer name.") - } + assert.Equal(t, "The Helm Team", f.Maintainers[0].Name, "Unexpected maintainer name.") - if f.Maintainers[1].Email != "nobody@example.com" { - t.Error("Unexpected maintainer email.") - } + assert.Equal(t, "nobody@example.com", f.Maintainers[1].Email, "Unexpected maintainer email.") - if len(f.Sources) != 1 { - t.Fatal("Unexpected number of sources") - } + require.Len(t, f.Sources, 1, "Unexpected number of sources") - if f.Sources[0] != "https://example.com/foo/bar" { - t.Errorf("Expected https://example.com/foo/bar, got %s", f.Sources) - } + assert.Equal(t, "https://example.com/foo/bar", f.Sources[0], "Expected https://example.com/foo/bar, got %s", f.Sources) - if f.Home != "http://example.com" { - t.Error("Unexpected home.") - } + assert.Equal(t, "http://example.com", f.Home, "Unexpected home.") - if f.Icon != "https://example.com/64x64.png" { - t.Errorf("Unexpected icon: %q", f.Icon) - } + assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) - if len(f.Keywords) != 3 { - t.Error("Unexpected keywords") - } + require.Len(t, f.Keywords, 3, "Unexpected keywords") - if len(f.Annotations) != 2 { - t.Fatal("Unexpected annotations") - } + require.Len(t, f.Annotations, 2, "Unexpected annotations") if want, got := "extravalue", f.Annotations["extrakey"]; want != got { t.Errorf("Want %q, but got %q", want, got) @@ -97,9 +74,7 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { - if kk[i] != k { - t.Errorf("Expected %q, got %q", kk[i], k) - } + assert.Equal(t, kk[i], k, "Expected %q, got %q", kk[i], k) } } diff --git a/internal/chart/v3/util/create_test.go b/internal/chart/v3/util/create_test.go index abdd52a82..d4b51eac0 100644 --- a/internal/chart/v3/util/create_test.go +++ b/internal/chart/v3/util/create_test.go @@ -22,6 +22,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/loader" ) @@ -30,20 +33,14 @@ func TestCreate(t *testing.T) { tdir := t.TempDir() c, err := Create("foo", tdir) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dir := filepath.Join(tdir, "foo") mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } + require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, @@ -81,13 +78,9 @@ func TestCreateFrom(t *testing.T) { dir := filepath.Join(tdir, "foo") c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } + require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, @@ -100,9 +93,7 @@ func TestCreateFrom(t *testing.T) { // Check each file to make sure has been replaced b, err := os.ReadFile(filepath.Join(dir, f)) - if err != nil { - t.Errorf("Unable to read file %s: %s", f, err) - } + require.NoError(t, err, "Unable to read file %s: %s", f, err) if bytes.Contains(b, []byte("")) { t.Errorf("File %s contains ", f) } @@ -131,17 +122,11 @@ func TestCreate_Overwrite(t *testing.T) { } data, err := os.ReadFile(tplname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if string(data) == "FOO" { - t.Fatal("File that should have been modified was not.") - } + require.NotEqual(t, "FOO", string(data), "File that should have been modified was not.") - if errlog.Len() == 0 { - t.Error("Expected warnings about overwriting files.") - } + assert.NotEqual(t, 0, errlog.Len(), "Expected warnings about overwriting files.") } func TestValidateChartName(t *testing.T) { diff --git a/internal/chart/v3/util/expand_test.go b/internal/chart/v3/util/expand_test.go index e9e298b81..a7a756485 100644 --- a/internal/chart/v3/util/expand_test.go +++ b/internal/chart/v3/util/expand_test.go @@ -72,9 +72,7 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff return nil }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = tw.Close() require.NoError(t, err) @@ -88,9 +86,7 @@ func TestExpand(t *testing.T) { dest := t.TempDir() reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if err := Expand(dest, reader); err != nil { t.Fatal(err) @@ -98,41 +94,29 @@ func TestExpand(t *testing.T) { expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if !fi.IsDir() { t.Fatalf("expected a chart directory at %s", expectedChartPath) } dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } @@ -168,41 +152,29 @@ func TestExpandFile(t *testing.T) { expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if !fi.IsDir() { t.Fatalf("expected a chart directory at %s", expectedChartPath) } dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index cbe9b853f..e729ad3b3 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -32,6 +32,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/loader" "helm.sh/helm/v4/pkg/chart/common" @@ -59,9 +62,7 @@ func TestSave(t *testing.T) { chartWithInvalidJSON := withSchema(*c, []byte("{")) where, err := Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save: %s", err) if !strings.HasPrefix(where, dest) { t.Fatalf("Expected %q to start with %q", where, dest) } @@ -70,12 +71,8 @@ func TestSave(t *testing.T) { } c2, err := loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } + require.NoError(t, err) + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { t.Fatal("Files data did not match") } @@ -92,19 +89,11 @@ func TestSave(t *testing.T) { c.Metadata.APIVersion = chart.APIVersionV3 where, err = Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save: %s", err) c2, err = loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Lock == nil { - t.Fatal("Expected v3 chart archive to contain a Chart.lock file") - } - if c2.Lock.Digest != c.Lock.Digest { - t.Fatal("Chart.lock data did not match") - } + require.NoError(t, err) + require.NotNil(t, c2.Lock, "Expected v3 chart archive to contain a Chart.lock file") + require.Equal(t, c.Lock.Digest, c2.Lock.Digest, "Chart.lock data did not match") }) } @@ -122,9 +111,7 @@ func TestSave(t *testing.T) { }, } _, err := Save(c, tmp) - if err == nil { - t.Fatal("Expected error saving chart with invalid name") - } + require.Error(t, err, "Expected error saving chart with invalid name") } // Creates a copy with a different schema; does not modify anything. @@ -165,14 +152,10 @@ func TestSavePreservesTimestamps(t *testing.T) { } where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save: %s", err) allHeaders, err := retrieveAllHeadersFromTar(where) - if err != nil { - t.Fatalf("Failed to parse tar: %v", err) - } + require.NoError(t, err, "Failed to parse tar: %v", err) roundedTime := initialCreateTime.Round(time.Second) for _, header := range allHeaders { @@ -234,37 +217,26 @@ func TestSaveDir(t *testing.T) { }, } - if err := SaveDir(c, tmp); err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, SaveDir(c, tmp), "Failed to save") c2, err := loader.LoadDir(tmp + "/ahab") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - if len(c2.Templates) != 1 || c2.Templates[0].Name != c.Templates[0].Name { - t.Fatal("Templates data did not match") - } + require.Len(t, c2.Templates, 1) + require.Equal(t, c.Templates[0].Name, c2.Templates[0].Name, "Templates data did not match") - if len(c2.Files) != 1 || c2.Files[0].Name != c.Files[0].Name { - t.Fatal("Files data did not match") - } + require.Len(t, c2.Files, 1) + require.Equal(t, c.Files[0].Name, c2.Files[0].Name, "Files data did not match") tmp2 := t.TempDir() c.Metadata.Name = "../ahab" pth := filepath.Join(tmp2, "tmpcharts") - if err := os.MkdirAll(filepath.Join(pth), 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(pth), 0o755), "Failed to create directory") - if err := SaveDir(c, pth); err.Error() != "\"../ahab\" is not a valid chart name" { - t.Fatalf("Did not get expected error for chart named %q", c.Name()) - } + err = SaveDir(c, pth) + assert.EqualError(t, err, "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) } func TestRepeatableSave(t *testing.T) { @@ -325,18 +297,12 @@ func TestRepeatableSave(t *testing.T) { // create package dest := path.Join(tmp, "newdir") where, err := Save(test.chart, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save: %s", err) // get shasum for package result, err := sha256Sum(where) - if err != nil { - t.Fatalf("Failed to check shasum: %s", err) - } + require.NoError(t, err, "Failed to check shasum: %s", err) // assert that the package SHA is what we wanted. - if result != test.want { - t.Errorf("FormatName() result = %v, want %v", result, test.want) - } + assert.Equal(t, test.want, result, "FormatName() result = %v, want %v", result, test.want) }) } } diff --git a/internal/plugin/subprocess_commands_test.go b/internal/plugin/subprocess_commands_test.go index dbce42f6a..6aa0a7435 100644 --- a/internal/plugin/subprocess_commands_test.go +++ b/internal/plugin/subprocess_commands_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPrepareCommand(t *testing.T) { @@ -36,12 +37,8 @@ func TestPrepareCommand(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(platformCommand, true, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, cmdArgs) { t.Fatalf("Expected %v, got %v", cmdArgs, args) } @@ -94,9 +91,7 @@ func TestPrepareCommandExtraArgs(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(platformCommand, true, testExtraArgs, env) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, tc.expected.cmdMain, cmd, "Expected command to match") assert.Equal(t, tc.expected.args, args, "Expected args to match") }) @@ -116,12 +111,8 @@ func TestPrepareCommands(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(cmds, true, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, cmdArgs) { t.Fatalf("Expected %v, got %v", cmdArgs, args) } @@ -143,12 +134,8 @@ func TestPrepareCommandsExtraArgs(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(cmds, true, extraArgs, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, expectedArgs) { t.Fatalf("Expected %v, got %v", expectedArgs, args) } @@ -166,12 +153,8 @@ func TestPrepareCommandsNoArch(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(cmds, true, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, cmdArgs) { t.Fatalf("Expected %v, got %v", cmdArgs, args) } @@ -189,12 +172,8 @@ func TestPrepareCommandsNoOsNoArch(t *testing.T) { env := map[string]string{} cmd, args, err := PrepareCommands(cmds, true, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, cmdArgs) { t.Fatalf("Expected %v, got %v", cmdArgs, args) } @@ -208,18 +187,16 @@ func TestPrepareCommandsNoMatch(t *testing.T) { } env := map[string]string{} - if _, _, err := PrepareCommands(cmds, true, []string{}, env); err == nil { - t.Fatal("Expected error to be returned") - } + _, _, err := PrepareCommands(cmds, true, []string{}, env) + require.Error(t, err, "Expected error to be returned") } func TestPrepareCommandsNoCommands(t *testing.T) { cmds := []PlatformCommand{} env := map[string]string{} - if _, _, err := PrepareCommands(cmds, true, []string{}, env); err == nil { - t.Fatal("Expected error to be returned") - } + _, _, err := PrepareCommands(cmds, true, []string{}, env) + require.Error(t, err, "Expected error to be returned") } func TestPrepareCommandsExpand(t *testing.T) { @@ -237,12 +214,8 @@ func TestPrepareCommandsExpand(t *testing.T) { } cmd, args, err := PrepareCommands(cmds, true, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, expectedArgs) { t.Fatalf("Expected %v, got %v", expectedArgs, args) } @@ -260,12 +233,8 @@ func TestPrepareCommandsNoExpand(t *testing.T) { } cmd, args, err := PrepareCommands(cmds, false, []string{}, env) - if err != nil { - t.Fatal(err) - } - if cmd != cmdMain { - t.Fatalf("Expected %q, got %q", cmdMain, cmd) - } + require.NoError(t, err) + require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) if !reflect.DeepEqual(args, cmdArgs) { t.Fatalf("Expected %v, got %v", cmdArgs, args) } From a02a5713deef0c0c1bf4359dcb0218a9c640224d Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Tue, 14 Jul 2026 23:50:53 +0200 Subject: [PATCH 069/161] chore: fix elseif and ifElseChain issues from gocritic (#32289) * chore: fix elseif and ifElseChain issues from gocritic Signed-off-by: Matthieu MOREL * test: enhance assertions in OCIInstaller and list tests using testify Signed-off-by: Matthieu MOREL --------- Signed-off-by: Matthieu MOREL --- .golangci.yml | 2 -- internal/chart/v3/lint/rules/chartfile.go | 10 +++--- internal/plugin/installer/installer.go | 9 ++--- .../plugin/installer/oci_installer_test.go | 17 ++++----- pkg/chart/common/util/coalesce.go | 10 +++--- pkg/chart/v2/lint/rules/chartfile.go | 10 +++--- pkg/cmd/list_test.go | 12 +++---- pkg/cmd/registry_login.go | 7 ++-- pkg/kube/client_test.go | 13 ++----- pkg/provenance/sign_test.go | 35 ++++++------------- pkg/pusher/ocipusher_test.go | 14 ++++---- pkg/registry/client.go | 6 ++-- pkg/registry/registry_test.go | 9 ++--- pkg/registry/transport.go | 7 ++-- pkg/storage/driver/memory_test.go | 31 +++++++--------- 15 files changed, 78 insertions(+), 114 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b9f43d434..6727d3001 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -87,10 +87,8 @@ linters: - badCall - commentedOutCode - deferInLoop - - elseif - exposedSyncMutex - hugeParam - - ifElseChain - importShadow - paramTypeCombine - ptrToRefParam diff --git a/internal/chart/v3/lint/rules/chartfile.go b/internal/chart/v3/lint/rules/chartfile.go index 6f51a1de5..db7ac61dc 100644 --- a/internal/chart/v3/lint/rules/chartfile.go +++ b/internal/chart/v3/lint/rules/chartfile.go @@ -160,14 +160,14 @@ func validateChartVersion(cf *chart.Metadata) error { func validateChartMaintainer(cf *chart.Metadata) error { for _, maintainer := range cf.Maintainers { - if maintainer == nil { + switch { + case maintainer == nil: return errors.New("a maintainer entry is empty") - } - if maintainer.Name == "" { + case maintainer.Name == "": return errors.New("each maintainer requires a name") - } else if maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email) { + case maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email): return fmt.Errorf("invalid email '%s' for maintainer '%s'", maintainer.Email, maintainer.Name) - } else if maintainer.URL != "" && !govalidator.IsURL(maintainer.URL) { + case maintainer.URL != "" && !govalidator.IsURL(maintainer.URL): return fmt.Errorf("invalid url '%s' for maintainer '%s'", maintainer.URL, maintainer.Name) } } diff --git a/internal/plugin/installer/installer.go b/internal/plugin/installer/installer.go index 865570773..4728879f5 100644 --- a/internal/plugin/installer/installer.go +++ b/internal/plugin/installer/installer.go @@ -136,15 +136,16 @@ func Update(i Installer) error { // NewForSource determines the correct Installer for the given source. func NewForSource(source, version string) (installer Installer, err error) { - if strings.HasPrefix(source, registry.OCIScheme+"://") { + switch { + case strings.HasPrefix(source, registry.OCIScheme+"://"): // Source is an OCI registry reference installer, err = NewOCIInstaller(source) - } else if isLocalReference(source) { + case isLocalReference(source): // Source is a local directory installer, err = NewLocalInstaller(source) - } else if isRemoteHTTPArchive(source) { + case isRemoteHTTPArchive(source): installer, err = NewHTTPInstaller(source) - } else { + default: installer, err = NewVCSInstaller(source, version) } diff --git a/internal/plugin/installer/oci_installer_test.go b/internal/plugin/installer/oci_installer_test.go index 650e46add..c3bebdb52 100644 --- a/internal/plugin/installer/oci_installer_test.go +++ b/internal/plugin/installer/oci_installer_test.go @@ -33,6 +33,8 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/cli" @@ -415,18 +417,11 @@ func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { // Install the plugin err = Install(installer) if tc.wantErr { - if err == nil { - t.Error("Expected installation to fail, but it succeeded") - } + require.Error(t, err, "Expected installation to fail, but it succeeded") } else { - if err != nil { - t.Errorf("Expected installation to succeed, got error: %v", err) - } else { - // Verify plugin was installed to the actual path - if !isPlugin(actualPath) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", actualPath) - } - } + require.NoError(t, err, "Expected installation to succeed, got error: %v", err) + // Verify plugin was installed to the actual path + assert.True(t, isPlugin(actualPath), "Expected plugin directory %s to contain plugin.yaml", actualPath) } }) } diff --git a/pkg/chart/common/util/coalesce.go b/pkg/chart/common/util/coalesce.go index 999eeb208..c1f73b16d 100644 --- a/pkg/chart/common/util/coalesce.go +++ b/pkg/chart/common/util/coalesce.go @@ -336,20 +336,22 @@ func coalesceTablesFullKey(printf printFn, dst, src map[string]any, prefix strin // values. for key, val := range src { fullkey := concatPrefix(prefix, key) - if dv, ok := dst[key]; ok && !merge && dv == nil && srcOriginalNonNil[key] { + dv, ok := dst[key] + switch { + case ok && !merge && dv == nil && srcOriginalNonNil[key]: // When coalescing (not merging), if dst has nil and src has a non-nil // value, the user is nullifying a chart default - remove the key. // But if src also has nil (or key not in src), preserve the nil delete(dst, key) - } else if !ok { + case !ok: dst[key] = val - } else if istable(val) { + case istable(val): if istable(dv) { coalesceTablesFullKey(printf, dv.(map[string]any), val.(map[string]any), fullkey, merge) } else { printf("warning: cannot overwrite table with non table for %s (%v)", fullkey, val) } - } else if istable(dv) && val != nil { + case istable(dv) && val != nil: printf("warning: destination for %s is a table. Ignoring non-table value (%v)", fullkey, val) } } diff --git a/pkg/chart/v2/lint/rules/chartfile.go b/pkg/chart/v2/lint/rules/chartfile.go index cb58bbac0..08508f46e 100644 --- a/pkg/chart/v2/lint/rules/chartfile.go +++ b/pkg/chart/v2/lint/rules/chartfile.go @@ -171,14 +171,14 @@ func validateChartVersionStrictSemVerV2(cf *chart.Metadata) error { func validateChartMaintainer(cf *chart.Metadata) error { for _, maintainer := range cf.Maintainers { - if maintainer == nil { + switch { + case maintainer == nil: return errors.New("a maintainer entry is empty") - } - if maintainer.Name == "" { + case maintainer.Name == "": return errors.New("each maintainer requires a name") - } else if maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email) { + case maintainer.Email != "" && !govalidator.IsEmail(maintainer.Email): return fmt.Errorf("invalid email '%s' for maintainer '%s'", maintainer.Email, maintainer.Name) - } else if maintainer.URL != "" && !govalidator.IsURL(maintainer.URL) { + case maintainer.URL != "" && !govalidator.IsURL(maintainer.URL): return fmt.Errorf("invalid url '%s' for maintainer '%s'", maintainer.URL, maintainer.Name) } } diff --git a/pkg/cmd/list_test.go b/pkg/cmd/list_test.go index 35153465a..f45616250 100644 --- a/pkg/cmd/list_test.go +++ b/pkg/cmd/list_test.go @@ -20,6 +20,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" @@ -348,13 +351,8 @@ func TestReleaseListWriter(t *testing.T) { t.Run(tt.name, func(t *testing.T) { writer := newReleaseListWriter(tt.releases, tt.timeFormat, tt.noHeaders, tt.noColor) - if writer == nil { - t.Error("Expected writer to be non-nil") - } else { - if len(writer.releases) != len(tt.releases) { - t.Errorf("Expected %d releases, got %d", len(tt.releases), len(writer.releases)) - } - } + require.NotNil(t, writer, "Expected writer to be non-nil") + assert.Len(t, writer.releases, len(tt.releases), "Expected %d releases, got %d", len(tt.releases), len(writer.releases)) }) } } diff --git a/pkg/cmd/registry_login.go b/pkg/cmd/registry_login.go index 1350fb244..bffc56445 100644 --- a/pkg/cmd/registry_login.go +++ b/pkg/cmd/registry_login.go @@ -96,14 +96,15 @@ func getUsernamePassword(usernameOpt string, passwordOpt string, passwordFromStd username := usernameOpt password := passwordOpt - if passwordFromStdinOpt { + switch { + case passwordFromStdinOpt: passwordFromStdin, err := io.ReadAll(os.Stdin) if err != nil { return "", "", err } password = strings.TrimSuffix(string(passwordFromStdin), "\n") password = strings.TrimSuffix(password, "\r") - } else if password == "" { + case password == "": if username == "" { username, err = readLine("Username: ", false) if err != nil { @@ -126,7 +127,7 @@ func getUsernamePassword(usernameOpt string, passwordOpt string, passwordFromStd return "", "", errors.New("password required") } } - } else { + default: slog.Warn("using --password via the CLI is insecure. Use --password-stdin") } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 4a28fc5ed..b5f1f5f12 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -1400,18 +1400,9 @@ func TestIsReachable(t *testing.T) { err := client.IsReachable() if tt.expectError { - if err == nil { - t.Error("expected error but got nil") - return - } - - if !strings.Contains(err.Error(), tt.errorContains) { - t.Errorf("expected error message to contain '%s', got: %v", tt.errorContains, err) - } + require.ErrorContains(t, err, tt.errorContains) } else { - if err != nil { - t.Errorf("expected no error but got: %v", err) - } + require.NoError(t, err) } }) } diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index faf402b43..3f8e654f9 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -362,41 +362,28 @@ func TestClearSignError(t *testing.T) { func TestVerify(t *testing.T) { signer, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Read the signature file data sigData, err := os.ReadFile(testSigBlock) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if ver, err := signer.Verify(archiveData, sigData, filepath.Base(testChartfile)); err != nil { - t.Errorf("Failed to pass verify. Err: %s", err) - } else if ver.FileHash == "" { - t.Error("Verification is missing hash.") - } else if ver.SignedBy == nil { - t.Error("No SignedBy field") - } else if ver.FileName != filepath.Base(testChartfile) { - t.Errorf("FileName is unexpectedly %q", ver.FileName) - } + ver, err := signer.Verify(archiveData, sigData, filepath.Base(testChartfile)) + require.NoError(t, err, "Failed to pass verify") + assert.NotEmpty(t, ver.FileHash, "Verification is missing hash.") + assert.NotNil(t, ver.SignedBy, "No SignedBy field") + assert.Equalf(t, filepath.Base(testChartfile), ver.FileName, "FileName is unexpectedly %q", ver.FileName) // Read the tampered signature file data tamperedSigData, err := os.ReadFile(testTamperedSigBlock) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err = signer.Verify(archiveData, tamperedSigData, filepath.Base(testChartfile)); err == nil { - t.Errorf("Expected %s to fail.", testTamperedSigBlock) - } + _, err = signer.Verify(archiveData, tamperedSigData, filepath.Base(testChartfile)) + require.Errorf(t, err, "Expected %s to fail.", testTamperedSigBlock) switch err.(type) { case pgperrors.SignatureError: diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index 52536dfd2..a4542500a 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/registry" ) @@ -378,16 +380,12 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { err = pusher.Push(chartRef, tt.href) if tt.expectError { - if err == nil { - t.Fatal("Expected error but got none") - } - if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { - t.Errorf("Expected error containing %q, got %q", tt.errorContains, err.Error()) + require.Error(t, err) + if tt.errorContains != "" { + require.ErrorContains(t, err, tt.errorContains) } } else { - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + require.NoError(t, err) } }) } diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 7a1c8f449..cba346dea 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -852,10 +852,8 @@ func (c *Client) ValidateReference(ref, version string, u *url.URL) (string, *ur if version == "" { // Use OCI URI tag as default version = registryReference.Tag - } else { - if registryReference.Tag != "" && registryReference.Tag != version { - return "", nil, fmt.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag) - } + } else if registryReference.Tag != "" && registryReference.Tag != version { + return "", nil, fmt.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag) } if registryReference.Digest != "" { diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 44af191b1..429b15113 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -200,7 +200,8 @@ func teardown(suite *TestRegistry) { func initCompromisedRegistryTestServer() string { s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if strings.Contains(r.URL.Path, "manifests") { + switch { + case strings.Contains(r.URL.Path, "manifests"): w.Header().Set("Content-Type", "application/vnd.oci.image.manifest.v1+json") w.WriteHeader(http.StatusOK) @@ -217,17 +218,17 @@ func initCompromisedRegistryTestServer() string { } ] }`, ConfigMediaType, ChartLayerMediaType) - } else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133" { + case r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133": w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("{\"name\":\"mychart\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\\n" + "an 'application' or a 'library' chart.\",\"apiVersion\":\"v2\",\"appVersion\":\"1.16.0\",\"type\":" + "\"application\"}")) - } else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" { + case r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb": w.Header().Set("Content-Type", ChartLayerMediaType) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("b")) - } else { + default: w.WriteHeader(http.StatusInternalServerError) } })) diff --git a/pkg/registry/transport.go b/pkg/registry/transport.go index 68e4ac587..beec43cdd 100644 --- a/pkg/registry/transport.go +++ b/pkg/registry/transport.go @@ -71,11 +71,12 @@ func (t *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, er slog.Debug(req.Method, "id", id, "url", req.URL, "header", logHeader(req.Header)) resp, err = t.RoundTripper.RoundTrip(req) - if err != nil { + switch { + case err != nil: slog.Debug("Response"[:len(req.Method)], "id", id, "error", err) - } else if resp != nil { + case resp != nil: slog.Debug("Response"[:len(req.Method)], "id", id, "status", resp.Status, "header", logHeader(resp.Header), "body", logResponseBody(resp)) - } else { + default: slog.Debug("Response"[:len(req.Method)], "id", id, "response", "nil") } diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index f821e30d4..6040daf59 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -261,27 +261,20 @@ func TestMemoryDelete(t *testing.T) { } startLen := len(start) for _, tt := range tests { - ts.SetNamespace(tt.namespace) + t.Run(tt.desc, func(t *testing.T) { + ts.SetNamespace(tt.namespace) - rel, err := ts.Delete(tt.key) - var rls *rspb.Release - if err == nil { - rls = convertReleaserToV1(t, rel) - } - if err != nil { - if !tt.err { - t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) + rel, err := ts.Delete(tt.key) + if tt.err { + require.Errorf(t, err, "Did not get expected error for %q '%s'\n", tt.desc, tt.key) + } else { + require.NoErrorf(t, err, "Failed %q to get '%s'", tt.desc, tt.key) + rls := convertReleaserToV1(t, rel) + require.Equalf(t, tt.key, fmt.Sprintf("%s.v%d", rls.Name, rls.Version), "Asked for delete on %s, but deleted %d", tt.key, rls.Version) } - continue - } else if tt.err { - t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) - } else if fmt.Sprintf("%s.v%d", rls.Name, rls.Version) != tt.key { - t.Fatalf("Asked for delete on %s, but deleted %d", tt.key, rls.Version) - } - _, err = ts.Get(tt.key) - if err == nil { - t.Error("Expected an error when asking for a deleted key") - } + _, err = ts.Get(tt.key) + require.Error(t, err, "Expected an error when asking for a deleted key") + }) } // Make sure that the deleted records are gone. From aa1ae3a36017156817e89e59eee0e88af9fc6365 Mon Sep 17 00:00:00 2001 From: Jakub Jaruszewski Date: Wed, 15 Jul 2026 00:37:53 +0200 Subject: [PATCH 070/161] Fix missing conflict retry with server-side apply (#32088) * Fix missing conflict retry with server-side apply Signed-off-by: Jakub Jaruszewski * Only retry on resourcequota transient conflict Signed-off-by: Jakub Jaruszewski * Use isServerSideRetryable + naming nitpick Signed-off-by: Jakub Jaruszewski --------- Signed-off-by: Jakub Jaruszewski --- pkg/kube/client.go | 46 ++++++++++++++++++++++++++++++++++------- pkg/kube/client_test.go | 25 +++++++++++++++++++++- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4e6d5c3a9..e363fad61 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -321,20 +321,24 @@ func (c *Client) makeCreateApplyFunc(serverSideApply, forceConflicts, dryRun boo slog.String("fieldValidationDirective", string(fieldValidationDirective))) return func(target *resource.Info) error { - err := patchResourceServerSide(target, dryRun, forceConflicts, fieldValidationDirective) - logger := c.Logger().With( slog.String("namespace", target.Namespace), slog.String("name", target.Name), slog.String("gvk", target.Mapping.GroupVersionKind.String())) - if err != nil { - logger.Debug("Error creating resource via patch", slog.Any("error", err)) - return err - } - logger.Debug("Created resource via patch") + return retry.OnError( + retry.DefaultRetry, + isServerSideRetryable, + func() error { + err := patchResourceServerSide(target, dryRun, forceConflicts, fieldValidationDirective) + if err != nil { + logger.Debug("Error creating resource via patch", slog.Any("error", err)) + return err + } - return nil + logger.Debug("Created resource via patch") + return nil + }) } } @@ -952,6 +956,32 @@ func isIncompatibleServerError(err error) bool { return err.(*apierrors.StatusError).Status().Code == http.StatusUnsupportedMediaType } +// isServerSideRetryable checks if an error encountered during server-side apply +// should be retried. Currently, only ResourceQuota conflicts are considered retryable. +func isServerSideRetryable(err error) bool { + return isResourceQuotaConflict(err) +} + +// isResourceQuotaConflict checks if the error is a conflict error specifically caused by +// a ResourceQuota. This is used to determine if a retry should be attempted, +// since quota conflicts are typically transient and can be resolved by retrying. +func isResourceQuotaConflict(err error) bool { + if !apierrors.IsConflict(err) { + return false + } + + // Check the error message for the specific ResourceQuota conflict pattern. + // The error message from the ResourceQuota admission controller contains: + // "Operation cannot be fulfilled on resourcequotas" and "the object has been modified" + errMsg := err.Error() + if strings.Contains(errMsg, "Operation cannot be fulfilled on resourcequotas") && + strings.Contains(errMsg, "the object has been modified") { + return true + } + + return false +} + // getManagedFieldsManager returns the manager string. If one was set it will be returned. // Otherwise, one is calculated based on the name of the binary. func getManagedFieldsManager() string { diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index b5f1f5f12..6421a2c2d 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -53,6 +53,7 @@ import ( k8sfake "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest/fake" + "k8s.io/client-go/util/retry" cmdtesting "k8s.io/kubectl/pkg/cmd/testing" ) @@ -273,8 +274,30 @@ func TestCreate(t *testing.T) { }, ExpectedErrorContains: "Operation cannot be fulfilled on resourcequotas \"quota\": the object has been modified; " + "please apply your changes to the latest version and try again", + ExpectedActions: func() []string { // expect helm to retry on conflict, workaround for: https://github.com/kubernetes/kubernetes/issues/67761 + actions := make([]string, retry.DefaultRetry.Steps) + for i := range actions { + actions[i] = "/namespaces/default/pods/dolphin:PATCH" + } + return actions + }(), + }, + "Create fail: managed fields conflict (server-side apply)": { + Pods: newPodList("seal"), + ServerSideApply: true, + Callback: func(t *testing.T, _ testCase, _ []RequestResponseAction, req *http.Request) (*http.Response, error) { + t.Helper() + + // Return a generic 409 conflict (not quota-related) + // This simulates a managed fields conflict + return &http.Response{ + StatusCode: http.StatusConflict, + Request: req, + }, nil + }, + ExpectedErrorContains: "the server reported a conflict", ExpectedActions: []string{ - "/namespaces/default/pods/dolphin:PATCH", + "/namespaces/default/pods/seal:PATCH", }, }, } From ad93b7df635d032a71201206cc3490e76b83bef4 Mon Sep 17 00:00:00 2001 From: Lohit Kolluri Date: Wed, 15 Jul 2026 06:52:09 +0530 Subject: [PATCH 071/161] feat: honor SOURCE_DATE_EPOCH for chart archives (#32162) * feat: honor SOURCE_DATE_EPOCH for chart archives Add StampModTimes() on Chart struct to recursively set ModTime on all chart file entries. CLI reads SOURCE_DATE_EPOCH env var and wires through all 5 commands: package, install, upgrade, dep build, dep update. Removes unused v3 duplicate source_date_epoch.go (YAGNI). Inlines env var parsing to CLI layer from chart util. Signed-off-by: Lohit Kolluri * docs: document SOURCE_DATE_EPOCH in environment variables help Add a short entry for $SOURCE_DATE_EPOCH to the env var table shown in 'helm help'. The variable is honored by 'helm package', 'install', 'upgrade', 'dep build', and 'dep update' to produce reproducible chart archives. Full documentation belongs in helm-www. Signed-off-by: Lohit Kolluri * fix: adapt SourceDateEpoch to upstream refactored dep check Upstream/main restructured the dependency error handling in install.go and upgrade.go from a nested-if block (if DependencyUpdate) to an early-return pattern (if !DependencyUpdate). Adapt the feature's Manager construction to match the new code structure. Signed-off-by: Lohit Kolluri --------- Signed-off-by: Lohit Kolluri --- pkg/action/package.go | 7 +++ pkg/chart/v2/chart.go | 31 ++++++++++++ pkg/chart/v2/util/save_test.go | 34 +++++++++++++ pkg/cmd/dependency_build.go | 5 ++ pkg/cmd/dependency_update.go | 5 ++ pkg/cmd/install.go | 5 ++ pkg/cmd/package.go | 6 +++ pkg/cmd/root.go | 1 + pkg/cmd/source_date_epoch.go | 42 ++++++++++++++++ pkg/cmd/source_date_epoch_test.go | 82 +++++++++++++++++++++++++++++++ pkg/cmd/upgrade.go | 5 ++ pkg/downloader/manager.go | 11 ++++- 12 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 pkg/cmd/source_date_epoch.go create mode 100644 pkg/cmd/source_date_epoch_test.go diff --git a/pkg/action/package.go b/pkg/action/package.go index 002203f40..1b7901f17 100644 --- a/pkg/action/package.go +++ b/pkg/action/package.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "syscall" + "time" "github.com/Masterminds/semver/v3" "golang.org/x/term" @@ -58,6 +59,8 @@ type Package struct { KeyFile string CaFile string InsecureSkipTLSVerify bool + // SourceDateEpoch, when set, normalizes chart timestamps for reproducible archives. + SourceDateEpoch *time.Time } const ( @@ -103,6 +106,10 @@ func (p *Package) Run(path string, _ map[string]any) (string, error) { ch.Metadata.AppVersion = p.AppVersion } + if p.SourceDateEpoch != nil { + ch.StampModTimes(*p.SourceDateEpoch) + } + if reqs := ac.MetaDependencies(); len(reqs) > 0 { if err := CheckDependencies(ch, reqs); err != nil { return "", err diff --git a/pkg/chart/v2/chart.go b/pkg/chart/v2/chart.go index 9d798b4de..9772754ce 100644 --- a/pkg/chart/v2/chart.go +++ b/pkg/chart/v2/chart.go @@ -177,6 +177,37 @@ func (ch *Chart) CRDObjects() []CRD { return crds } +// StampModTimes sets timestamps on the chart (and dependencies) to epoch. +// This is used for reproducible builds via SOURCE_DATE_EPOCH. +func (ch *Chart) StampModTimes(epoch time.Time) { + ch.ModTime = epoch + if len(ch.Schema) > 0 { + ch.SchemaModTime = epoch + } + if ch.Lock != nil { + ch.Lock.Generated = epoch + } + + for _, f := range ch.Raw { + if f != nil { + f.ModTime = epoch + } + } + for _, f := range ch.Templates { + if f != nil { + f.ModTime = epoch + } + } + for _, f := range ch.Files { + if f != nil { + f.ModTime = epoch + } + } + for _, dep := range ch.Dependencies() { + dep.StampModTimes(epoch) + } +} + func hasManifestExtension(fname string) bool { ext := filepath.Ext(fname) return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".json") diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index 635158e9c..55c67f49e 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -231,6 +231,40 @@ func TestSavePreservesTimestamps(t *testing.T) { } } +func TestSaveWithSourceDateEpoch(t *testing.T) { + epoch := time.Unix(1609459200, 0).UTC() + tmp := t.TempDir() + c := &chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: chart.APIVersionV2, + Name: "ahab", + Version: "1.2.3", + }, + Files: []*common.File{ + {Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")}, + }, + Schema: []byte("{\n \"title\": \"Values\"\n}"), + } + + c.StampModTimes(epoch) + where, err := Save(c, tmp) + if err != nil { + t.Fatalf("Failed to save: %s", err) + } + + allHeaders, err := retrieveAllHeadersFromTar(where) + if err != nil { + t.Fatalf("Failed to parse tar: %v", err) + } + + expected := epoch.Round(time.Second) + for _, header := range allHeaders { + if !header.ModTime.Equal(expected) { + t.Fatalf("Expected SOURCE_DATE_EPOCH timestamp %v, got %v for %q", expected, header.ModTime, header.Name) + } + } +} + // We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function // as well, so we are not duplicating components of the code which iterate // through the tar. diff --git a/pkg/cmd/dependency_build.go b/pkg/cmd/dependency_build.go index f572fbae1..85c385670 100644 --- a/pkg/cmd/dependency_build.go +++ b/pkg/cmd/dependency_build.go @@ -55,6 +55,10 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command { if len(args) > 0 { chartpath = filepath.Clean(args[0]) } + sourceDateEpoch, err := sourceDateEpochFromEnv() + if err != nil { + return err + } registryClient, err := newRegistryClient(out, client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSVerify, client.PlainHTTP, client.Username, client.Password) if err != nil { @@ -72,6 +76,7 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command { RepositoryCache: settings.RepositoryCache, ContentCache: settings.ContentCache, Debug: settings.Debug, + SourceDateEpoch: sourceDateEpoch, } if client.Verify { man.Verify = downloader.VerifyIfPossible diff --git a/pkg/cmd/dependency_update.go b/pkg/cmd/dependency_update.go index a7131e587..0db36553c 100644 --- a/pkg/cmd/dependency_update.go +++ b/pkg/cmd/dependency_update.go @@ -58,6 +58,10 @@ func newDependencyUpdateCmd(_ *action.Configuration, out io.Writer) *cobra.Comma if len(args) > 0 { chartpath = filepath.Clean(args[0]) } + sourceDateEpoch, err := sourceDateEpochFromEnv() + if err != nil { + return err + } registryClient, err := newRegistryClient(out, client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSVerify, client.PlainHTTP, client.Username, client.Password) if err != nil { @@ -75,6 +79,7 @@ func newDependencyUpdateCmd(_ *action.Configuration, out io.Writer) *cobra.Comma RepositoryCache: settings.RepositoryCache, ContentCache: settings.ContentCache, Debug: settings.Debug, + SourceDateEpoch: sourceDateEpoch, } if client.Verify { man.Verify = downloader.VerifyAlways diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index c7aa2c542..b935ed4d0 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -297,6 +297,10 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options } if req := ac.MetaDependencies(); len(req) > 0 { + sourceDateEpoch, err := sourceDateEpochFromEnv() + if err != nil { + return nil, err + } // If CheckDependencies returns an error, we have unfulfilled dependencies. // As of Helm 2.4.0, this is treated as a stopping condition: // https://github.com/helm/helm/issues/2209 @@ -315,6 +319,7 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options ContentCache: settings.ContentCache, Debug: settings.Debug, RegistryClient: client.GetRegistryClient(), + SourceDateEpoch: sourceDateEpoch, } if err := man.Update(); err != nil { return nil, err diff --git a/pkg/cmd/package.go b/pkg/cmd/package.go index 46133d971..7e240c8d0 100644 --- a/pkg/cmd/package.go +++ b/pkg/cmd/package.go @@ -59,6 +59,11 @@ func newPackageCmd(out io.Writer) *cobra.Command { if len(args) == 0 { return errors.New("need at least one argument, the path to the chart") } + sourceDateEpoch, err := sourceDateEpochFromEnv() + if err != nil { + return err + } + client.SourceDateEpoch = sourceDateEpoch if client.Sign { if client.Key == "" { return errors.New("--key is required for signing a package") @@ -101,6 +106,7 @@ func newPackageCmd(out io.Writer) *cobra.Command { RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, ContentCache: settings.ContentCache, + SourceDateEpoch: sourceDateEpoch, } if err := downloadManager.Update(); err != nil { diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 7ee71f4ef..28798de5c 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -84,6 +84,7 @@ Environment variables: | $HELM_QPS | set the Queries Per Second in cases where a high number of calls exceed the option for higher burst values | | $HELM_COLOR | set color output mode. Allowed values: never, always, auto (default: never) | | $NO_COLOR | set to any non-empty value to disable all colored output (overrides $HELM_COLOR) | +| $SOURCE_DATE_EPOCH | set a Unix timestamp for reproducible chart archives | Helm stores cache, configuration, and data based on the following configuration order: diff --git a/pkg/cmd/source_date_epoch.go b/pkg/cmd/source_date_epoch.go new file mode 100644 index 000000000..6f73e3b30 --- /dev/null +++ b/pkg/cmd/source_date_epoch.go @@ -0,0 +1,42 @@ +/* +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 cmd + +import ( + "errors" + "fmt" + "os" + "strconv" + "time" +) + +// sourceDateEpochFromEnv returns SOURCE_DATE_EPOCH when set, or nil when unset. +func sourceDateEpochFromEnv() (*time.Time, error) { + epochStr, ok := os.LookupEnv("SOURCE_DATE_EPOCH") + if !ok || epochStr == "" { + return nil, nil + } + epoch, err := strconv.ParseInt(epochStr, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid SOURCE_DATE_EPOCH: %w", err) + } + if epoch < 0 { + return nil, errors.New("invalid SOURCE_DATE_EPOCH: must not be negative") + } + t := time.Unix(epoch, 0).UTC() + return &t, nil +} diff --git a/pkg/cmd/source_date_epoch_test.go b/pkg/cmd/source_date_epoch_test.go new file mode 100644 index 000000000..719de7c90 --- /dev/null +++ b/pkg/cmd/source_date_epoch_test.go @@ -0,0 +1,82 @@ +/* +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 cmd + +import ( + "testing" + "time" +) + +func TestSourceDateEpochFromEnv(t *testing.T) { + t.Setenv("SOURCE_DATE_EPOCH", "1609459200") + + got, err := sourceDateEpochFromEnv() + if err != nil { + t.Fatalf("sourceDateEpochFromEnv() error: %v", err) + } + if got == nil { + t.Fatal("expected non-nil epoch") + } + want := time.Unix(1609459200, 0).UTC() + if !got.Equal(want) { + t.Fatalf("expected %v, got %v", want, *got) + } +} + +func TestSourceDateEpochFromEnvUnset(t *testing.T) { + t.Setenv("SOURCE_DATE_EPOCH", "") + + got, err := sourceDateEpochFromEnv() + if err != nil { + t.Fatalf("sourceDateEpochFromEnv() error: %v", err) + } + if got != nil { + t.Fatalf("expected nil epoch, got %v", *got) + } +} + +func TestSourceDateEpochFromEnvInvalid(t *testing.T) { + t.Setenv("SOURCE_DATE_EPOCH", "not-a-number") + + if _, err := sourceDateEpochFromEnv(); err == nil { + t.Fatal("expected error for invalid SOURCE_DATE_EPOCH") + } +} + +func TestSourceDateEpochFromEnvNegative(t *testing.T) { + t.Setenv("SOURCE_DATE_EPOCH", "-1") + + if _, err := sourceDateEpochFromEnv(); err == nil { + t.Fatal("expected error for negative SOURCE_DATE_EPOCH") + } +} + +func TestSourceDateEpochFromEnvZero(t *testing.T) { + t.Setenv("SOURCE_DATE_EPOCH", "0") + + got, err := sourceDateEpochFromEnv() + if err != nil { + t.Fatalf("sourceDateEpochFromEnv() error: %v", err) + } + if got == nil { + t.Fatal("expected non-nil epoch") + } + want := time.Unix(0, 0).UTC() + if !got.Equal(want) { + t.Fatalf("expected %v, got %v", want, *got) + } +} diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index a6aa96129..c038a2149 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -204,6 +204,10 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return err } if req := ac.MetaDependencies(); len(req) > 0 { + sourceDateEpoch, err := sourceDateEpochFromEnv() + if err != nil { + return err + } if err := action.CheckDependencies(ch, req); err != nil { err = fmt.Errorf("an error occurred while checking for chart dependencies. You may need to run 'helm dependency build' to fetch missing dependencies: %w", err) if !client.DependencyUpdate { @@ -219,6 +223,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { RepositoryCache: settings.RepositoryCache, ContentCache: settings.ContentCache, Debug: settings.Debug, + SourceDateEpoch: sourceDateEpoch, } if err := man.Update(); err != nil { return err diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 1203eb991..a1fa0ddbd 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -29,6 +29,7 @@ import ( "regexp" "strings" "sync" + "time" "github.com/Masterminds/semver/v3" "sigs.k8s.io/yaml" @@ -78,6 +79,8 @@ type Manager struct { // ContentCache is a location where a cache of charts can be stored ContentCache string + // SourceDateEpoch, when set, normalizes chart timestamps for reproducible archives. + SourceDateEpoch *time.Time } // Build rebuilds a local charts directory from a lockfile. @@ -303,7 +306,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { if m.Debug { fmt.Fprintf(m.Out, "Archiving %s from repo %s\n", dep.Name, dep.Repository) } - ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version, tmpPath) + ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version, tmpPath, m.SourceDateEpoch) if err != nil { saveError = err break @@ -867,7 +870,7 @@ func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error { } // archive a dep chart from local directory and save it into destPath -func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, error) { +func tarFromLocalDir(chartpath, name, repo, version, destPath string, sourceDateEpoch *time.Time) (string, error) { if !strings.HasPrefix(repo, "file://") { return "", fmt.Errorf("wrong format: chart %s repository %s", name, repo) } @@ -882,6 +885,10 @@ func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, e return "", err } + if sourceDateEpoch != nil { + ch.StampModTimes(*sourceDateEpoch) + } + constraint, err := semver.NewConstraint(version) if err != nil { return "", fmt.Errorf("dependency %s has an invalid version/constraint format: %w", name, err) From caac755f199adf5ac4fbbc8c46a741d004ed7276 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Jul 2026 00:24:50 +0200 Subject: [PATCH 072/161] chore(internal): refactor: convert tests to testify assert/require part 3 refactor: convert tests to testify assert/require in internal/chart/v3/lint/rules Signed-off-by: Matthieu MOREL --- internal/chart/v3/chart_test.go | 10 ++-- .../chart/v3/lint/rules/dependencies_test.go | 23 ++++------ internal/chart/v3/lint/rules/values_test.go | 39 +++++----------- internal/chart/v3/loader/load_test.go | 5 +- internal/chart/v3/metadata_test.go | 20 +++----- internal/chart/v3/util/compatible_test.go | 10 ++-- internal/plugin/sign_test.go | 46 ++++++------------- 7 files changed, 53 insertions(+), 100 deletions(-) diff --git a/internal/chart/v3/chart_test.go b/internal/chart/v3/chart_test.go index d5d066d9b..554dde2c1 100644 --- a/internal/chart/v3/chart_test.go +++ b/internal/chart/v3/chart_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" ) @@ -76,15 +77,12 @@ func TestSaveChartNoRawData(t *testing.T) { } is := assert.New(t) + req := require.New(t) data, err := json.Marshal(chrt) - if err != nil { - t.Fatal(err) - } + req.NoError(err) res := &Chart{} - if err := json.Unmarshal(data, res); err != nil { - t.Fatal(err) - } + req.NoError(json.Unmarshal(data, res)) is.Equal([]*common.File(nil), res.Raw) } diff --git a/internal/chart/v3/lint/rules/dependencies_test.go b/internal/chart/v3/lint/rules/dependencies_test.go index 31fd0ef33..ae5882110 100644 --- a/internal/chart/v3/lint/rules/dependencies_test.go +++ b/internal/chart/v3/lint/rules/dependencies_test.go @@ -19,6 +19,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/internal/chart/v3/lint/support" chartutil "helm.sh/helm/v4/internal/chart/v3/util" @@ -63,17 +66,13 @@ func chartWithBadDependencies() chart.Chart { func TestValidateDependencyInChartsDir(t *testing.T) { c := chartWithBadDependencies() - if err := validateDependencyInChartsDir(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart directory") - } + assert.Error(t, validateDependencyInChartsDir(&c), "chart should have been flagged for missing deps in chart directory") } func TestValidateDependencyInMetadata(t *testing.T) { c := chartWithBadDependencies() - if err := validateDependencyInMetadata(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart metadata") - } + assert.Error(t, validateDependencyInMetadata(&c), "chart should have been flagged for missing deps in chart metadata") } func TestValidateDependenciesUnique(t *testing.T) { @@ -131,9 +130,7 @@ func TestValidateDependenciesUnique(t *testing.T) { } for _, tt := range tests { - if err := validateDependenciesUnique(&tt.chart); err == nil { - t.Error("chart should have been flagged for dependency shadowing") - } + assert.Error(t, validateDependenciesUnique(&tt.chart), "chart should have been flagged for dependency shadowing") } } @@ -141,15 +138,11 @@ func TestDependencies(t *testing.T) { tmp := t.TempDir() c := chartWithBadDependencies() - err := chartutil.SaveDir(&c, tmp) - if err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&c, tmp)) linter := support.Linter{ChartDir: filepath.Join(tmp, c.Metadata.Name)} Dependencies(&linter) - if l := len(linter.Messages); l != 2 { - t.Errorf("expected 2 linter errors for bad chart dependencies. Got %d.", l) + if !assert.Len(t, linter.Messages, 2, "expected 2 linter errors for bad chart dependencies") { for i, msg := range linter.Messages { t.Logf("Message: %d, Error: %#v", i, msg) } diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index 470904049..c87607f2d 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" ) @@ -56,9 +57,7 @@ func TestValidateValuesYamlNotDirectory(t *testing.T) { defer os.Remove(nonExistingValuesFilePath) err := validateValuesFileExistence(nonExistingValuesFilePath) - if err == nil { - t.Error("validateValuesFileExistence to return a linter error, got no error") - } + assert.Error(t, err, "validateValuesFileExistence to return a linter error, got no error") } func TestValidateValuesFileWellFormed(t *testing.T) { @@ -67,9 +66,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err == nil { - t.Fatal("expected values file to fail parsing") - } + require.Error(t, validateValuesFile(valfile, map[string]any{}, false), "expected values file to fail parsing") } func TestValidateValuesFileSchema(t *testing.T) { @@ -78,9 +75,7 @@ func TestValidateValuesFileSchema(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoError(t, validateValuesFile(valfile, map[string]any{}, false), "Failed validation") } func TestValidateValuesFileSchemaFailure(t *testing.T) { @@ -91,8 +86,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { valfile := filepath.Join(tmpdir, "values.yaml") - err := validateValuesFile(valfile, map[string]any{}, false) - assert.ErrorContains(t, err, "- at '/username': got number, want string") + assert.ErrorContains(t, validateValuesFile(valfile, map[string]any{}, false), "- at '/username': got number, want string") } func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { @@ -103,10 +97,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T valfile := filepath.Join(tmpdir, "values.yaml") - err := validateValuesFile(valfile, map[string]any{}, true) - if err != nil { - t.Fatal("expected values file to pass parsing because of skipSchemaValidation") - } + require.NoError(t, validateValuesFile(valfile, map[string]any{}, true), "expected values file to pass parsing because of skipSchemaValidation") } func TestValidateValuesFileSchemaOverrides(t *testing.T) { @@ -118,9 +109,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoError(t, validateValuesFile(valfile, overrides, false), "Failed validation") } func TestValidateValuesFile(t *testing.T) { @@ -157,12 +146,10 @@ func TestValidateValuesFile(t *testing.T) { err := validateValuesFile(valfile, tt.overrides, false) - switch { - case err != nil && tt.errorMessage == "": - t.Errorf("Failed validation with %s", err) - case err == nil && tt.errorMessage != "": - t.Error("expected values file to fail parsing") - case err != nil && tt.errorMessage != "": + if tt.errorMessage == "" { + require.NoError(t, err, "Failed validation") + } else { + require.Error(t, err, "expected values file to fail parsing") assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") } }) @@ -172,8 +159,6 @@ func TestValidateValuesFile(t *testing.T) { func createTestingSchema(t *testing.T, dir string) string { t.Helper() schemafile := filepath.Join(dir, "values.schema.json") - if err := os.WriteFile(schemafile, []byte(testSchema), 0o700); err != nil { - t.Fatalf("Failed to write schema to tmpdir: %s", err) - } + require.NoError(t, os.WriteFile(schemafile, []byte(testSchema), 0o700), "Failed to write schema to tmpdir") return schemafile } diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index 1c5845da6..5caec7815 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -31,6 +31,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" chart "helm.sh/helm/v4/internal/chart/v3" @@ -690,9 +691,7 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { if dep.Templates[0].Name != "templates/alpine-pod.yaml" { t.Errorf("Unexpected template: %s", dep.Templates[0].Name) } - if len(dep.Templates[0].Data) == 0 { - t.Error("No template data.") - } + assert.NotEmpty(t, dep.Templates[0].Data, "No template data.") if len(dep.Files) != 1 { t.Fatalf("Expected 1 Files, got %d", len(dep.Files)) } diff --git a/internal/chart/v3/metadata_test.go b/internal/chart/v3/metadata_test.go index 5f88552e9..91b917980 100644 --- a/internal/chart/v3/metadata_test.go +++ b/internal/chart/v3/metadata_test.go @@ -16,8 +16,10 @@ limitations under the License. package v3 import ( - "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { @@ -192,21 +194,13 @@ func TestValidate(t *testing.T) { for _, tt := range tests { result := tt.md.Validate() - if !errors.Is(result, tt.err) { - t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name) - } + assert.ErrorIsf(t, result, tt.err, "expected %q, got %q in test %q", tt.err, result, tt.name) } } func TestValidate_sanitize(t *testing.T) { md := &Metadata{APIVersion: "3", Name: "test", Version: "1.0", Description: "\adescr\u0081iption\rtest", Maintainers: []*Maintainer{{Name: "\r"}}} - if err := md.Validate(); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if md.Description != "description test" { - t.Fatalf("description was not sanitized: %q", md.Description) - } - if md.Maintainers[0].Name != " " { - t.Fatal("maintainer name was not sanitized") - } + require.NoError(t, md.Validate()) + require.Equalf(t, "description test", md.Description, "description was not sanitized: %q", md.Description) + require.Equal(t, " ", md.Maintainers[0].Name, "maintainer name was not sanitized") } diff --git a/internal/chart/v3/util/compatible_test.go b/internal/chart/v3/util/compatible_test.go index e17d33e35..b210d3dd8 100644 --- a/internal/chart/v3/util/compatible_test.go +++ b/internal/chart/v3/util/compatible_test.go @@ -17,7 +17,11 @@ limitations under the License. // Package version represents the current version of the project. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestIsCompatibleRange(t *testing.T) { tests := []struct { @@ -36,8 +40,6 @@ func TestIsCompatibleRange(t *testing.T) { } for _, tt := range tests { - if IsCompatibleRange(tt.constraint, tt.ver) != tt.expected { - t.Errorf("expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) - } + assert.Equalf(t, tt.expected, IsCompatibleRange(tt.constraint, tt.ver), "expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) } } diff --git a/internal/plugin/sign_test.go b/internal/plugin/sign_test.go index 7e97a82aa..d6fd4c548 100644 --- a/internal/plugin/sign_test.go +++ b/internal/plugin/sign_test.go @@ -18,9 +18,11 @@ package plugin import ( "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/provenance" ) @@ -28,9 +30,7 @@ func TestSignPlugin(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file pluginYAML := `apiVersion: v1 @@ -41,16 +41,12 @@ version: 1.0.0 runtimeConfig: platformCommand: - command: echo` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644)) // Create a tarball tarballPath := filepath.Join(tempDir, "test-plugin.tgz") tarFile, err := os.Create(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if err := CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { tarFile.Close() t.Fatal(err) @@ -60,39 +56,25 @@ runtimeConfig: // Create a test key for signing keyring := "../../pkg/cmd/testdata/helm-test-key.secret" signer, err := provenance.NewFromKeyring(keyring, "helm-test") - if err != nil { - t.Fatal(err) - } - if err := signer.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, err) + require.NoError(t, signer.DecryptKey(func(_ string) ([]byte, error) { return []byte(""), nil - }); err != nil { - t.Fatal(err) - } + })) // Read the tarball data tarballData, err := os.ReadFile(tarballPath) - if err != nil { - t.Fatalf("failed to read tarball: %v", err) - } + require.NoError(t, err, "failed to read tarball") // Sign the plugin tarball sig, err := SignPlugin(tarballData, filepath.Base(tarballPath), signer) - if err != nil { - t.Fatalf("failed to sign plugin: %v", err) - } + require.NoError(t, err, "failed to sign plugin") // Verify the signature contains the expected content - if !strings.Contains(sig, "-----BEGIN PGP SIGNED MESSAGE-----") { - t.Error("signature does not contain PGP header") - } + assert.Contains(t, sig, "-----BEGIN PGP SIGNED MESSAGE-----", "signature does not contain PGP header") // Verify the tarball hash is in the signature expectedHash, err := provenance.DigestFile(tarballPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // The signature should contain the tarball hash - if !strings.Contains(sig, "sha256:"+expectedHash) { - t.Errorf("signature does not contain expected tarball hash: sha256:%s", expectedHash) - } + assert.Contains(t, sig, "sha256:"+expectedHash, "signature does not contain expected tarball hash: sha256:%s", expectedHash) } From 96a25ab4f86c2c78de2acfe45a69c0a40055aa3c Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Wed, 15 Jul 2026 16:48:15 -0700 Subject: [PATCH 073/161] fix: 'gocritic: filepathJoin path seperator' lint error Signed-off-by: George Jenkins --- pkg/helmpath/lazypath_darwin_test.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/pkg/helmpath/lazypath_darwin_test.go b/pkg/helmpath/lazypath_darwin_test.go index 143750f04..8d61334f8 100644 --- a/pkg/helmpath/lazypath_darwin_test.go +++ b/pkg/helmpath/lazypath_darwin_test.go @@ -36,13 +36,12 @@ func TestDataPath(t *testing.T) { os.Unsetenv(xdg.DataHomeEnvVar) expected := filepath.Join(homedir.HomeDir(), "Library", appName, testFile) - assert.Equal(t, expected, lazy.dataPath(testFile)) - t.Setenv(xdg.DataHomeEnvVar, "/tmp") - - expected = filepath.Join("/tmp", appName, testFile) + tmpDir := t.TempDir() + t.Setenv(xdg.DataHomeEnvVar, tmpDir) + expected = filepath.Join(tmpDir, appName, testFile) assert.Equal(t, expected, lazy.dataPath(testFile)) } @@ -50,13 +49,12 @@ func TestConfigPath(t *testing.T) { os.Unsetenv(xdg.ConfigHomeEnvVar) expected := filepath.Join(homedir.HomeDir(), "Library", "Preferences", appName, testFile) - assert.Equal(t, expected, lazy.configPath(testFile)) - t.Setenv(xdg.ConfigHomeEnvVar, "/tmp") - - expected = filepath.Join("/tmp", appName, testFile) + tmpDir := t.TempDir() + t.Setenv(xdg.ConfigHomeEnvVar, tmpDir) + expected = filepath.Join(tmpDir, appName, testFile) assert.Equal(t, expected, lazy.configPath(testFile)) } @@ -64,12 +62,11 @@ func TestCachePath(t *testing.T) { os.Unsetenv(xdg.CacheHomeEnvVar) expected := filepath.Join(homedir.HomeDir(), "Library", "Caches", appName, testFile) - assert.Equal(t, expected, lazy.cachePath(testFile)) - t.Setenv(xdg.CacheHomeEnvVar, "/tmp") - - expected = filepath.Join("/tmp", appName, testFile) + tmpDir := t.TempDir() + t.Setenv(xdg.CacheHomeEnvVar, tmpDir) + expected = filepath.Join(tmpDir, appName, testFile) assert.Equal(t, expected, lazy.cachePath(testFile)) } From 9f3c89a4b50e99a46c23b6942b87b205bdd8c33f Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Thu, 16 Jul 2026 09:29:59 +0200 Subject: [PATCH 074/161] ci: auto-label PRs targeting main with v4.x Mirrors the dev-v3 labeling workflow from #32340, reusing the existing v4.x label since main tracks the upcoming v4 release. Signed-off-by: Benoit Tigeot --- .github/labeler.yml | 2 ++ .github/workflows/label-pr.yml | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/label-pr.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..46d20af9c --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +"v4.x": + - base-branch: "main" diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 000000000..5c2b2fa17 --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,16 @@ +name: Label PRs +on: + pull_request_target: + branches: [main] + types: [opened, reopened, edited, synchronize] +permissions: {} +jobs: + label: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # pin@v6.2.0 + with: + sync-labels: true From 8cd3a48c34136f14fa6ba60554ef5ab0e12625be Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Thu, 16 Jul 2026 11:14:59 -0700 Subject: [PATCH 075/161] chore: Add AI Vendor specific paths to `.gitignore` Signed-off-by: George Jenkins --- .gitignore | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2209e9809..08c6b535e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ .DS_Store .coverage/ .idea -.claude .vimrc .vscode/ .devcontainer/ @@ -11,7 +10,14 @@ _dist/ _dist_versions/ bin/ vendor/ +.pre-commit-config.yaml + # Ignores charts pulled for dependency build tests cmd/helm/testdata/testcharts/issue-7233/charts/* pkg/cmd/testdata/testcharts/issue-7233/charts/* -.pre-commit-config.yaml + +# AI Vendor specific paths +CLAUDE.md +.claude/ +.codex/ +.cursor/ From eeb37edfeafffdb562b97774f85a394332cf58dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:32:51 +0000 Subject: [PATCH 076/161] chore(deps): bump github/codeql-action/autobuild from 4.37.0 to 4.37.1 Bumps [github/codeql-action/autobuild](https://github.com/github/codeql-action) from 4.37.0 to 4.37.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a) --- updated-dependencies: - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e87ec8ec2..52c045e85 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl From a494169853d1e6f752eb838fedbb00d1a8593b66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 05:44:01 -0600 Subject: [PATCH 077/161] chore(deps): bump actions/setup-go from 6.5.0 to 7.0.0 (#32376) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.5.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/924ae3a1cded613372ab5595356fb5720e22ba16...b7ad1dad31e06c5925ef5d2fc7ad053ef454303e) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-test.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/govulncheck.yml | 2 +- .github/workflows/release.yml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index b4ce89f26..066adf1ce 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -22,7 +22,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 6355db230..c5312e936 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -17,7 +17,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index c7c9b3d53..0aee4c01c 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -25,7 +25,7 @@ jobs: - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee2612917..3bed1e12a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true @@ -93,7 +93,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true From 06b95860dc2419062834a5e59921569676b45031 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 05:44:39 -0600 Subject: [PATCH 078/161] chore(deps): bump github/codeql-action/upload-sarif (#32378) Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.37.0 to 4.37.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 343669859..3a8410ced 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: sarif_file: results.sarif From 0563162dd95dcff0f7b1ac09e0c784ae21b72245 Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Fri, 17 Jul 2026 05:51:11 -0600 Subject: [PATCH 079/161] chore(deps): bump github/codeql-action init and analyze to 4.37.1 Signed-off-by: Terry Howe --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 52c045e85..b0a03b342 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 From 5a30c7ae8504218fd68d87c5a7d929d0a3bb3891 Mon Sep 17 00:00:00 2001 From: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:00:17 -0500 Subject: [PATCH 080/161] fix(scripts): add cache-busting to get-helm-3 version check The get-helm-3 script queries get.helm.sh/helm3-latest-version to determine the latest release. The CDN serving this file has no Cache-Control header, so edge servers can serve stale cached responses for hours after a new release. This causes non-deterministic behavior: machines running get-helm-3 at the same time can install different versions depending on which CDN edge node they hit. Fix: Append a timestamp query string (?ts=1783837438) to bust CDN caches, and add Cache-Control: no-cache header to both curl and wget requests. Fixes #32329 Signed-off-by: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> --- scripts/get-helm-3 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 5f265a52f..dad66ab20 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -114,12 +114,14 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL - local latest_release_url="https://get.helm.sh/helm3-latest-version" + # Append a cache-busting query string to avoid CDN edge servers + # serving stale version files after a new release. + local latest_release_url="https://get.helm.sh/helm3-latest-version?ts=$(date +%s)" local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then - latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true ) + latest_release_response=$( curl -L --silent --show-error --fail -H "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) elif [ "${HAS_WGET}" == "true" ]; then - latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true ) + latest_release_response=$( wget "$latest_release_url" --header="Cache-Control: no-cache" -q -O - 2>&1 || true ) fi TAG=$( echo "$latest_release_response" | grep '^v[0-9]' ) if [ "x$TAG" == "x" ]; then From a2b1a60d51223254bd9c2f08cf3f411eb9d9fc58 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Sat, 18 Jul 2026 13:28:03 +0200 Subject: [PATCH 081/161] fix: enhance error handling and improve test assertions (#32352) Signed-off-by: Matthieu MOREL --- .golangci.yml | 4 +-- .../chart/v3/lint/rules/deprecations_test.go | 8 ++---- internal/plugin/runtime_subprocess.go | 7 +++-- internal/sympath/walk.go | 9 +++--- pkg/chart/v2/lint/rules/deprecations_test.go | 13 +++++---- pkg/chart/v2/lint/rules/template_test.go | 10 ++++--- pkg/chart/v2/util/dependencies_test.go | 10 +++---- pkg/cmd/plugin_test.go | 28 ++++++------------- pkg/kube/client.go | 7 +++-- pkg/provenance/sign_test.go | 8 ++---- pkg/registry/transport.go | 3 +- pkg/repo/v1/index.go | 4 +-- pkg/strvals/parser.go | 22 +++++++-------- 13 files changed, 63 insertions(+), 70 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 6727d3001..5b6d7cf8e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -74,9 +74,9 @@ linters: errorlint: # Check for plain type assertions and type switches. - asserts: false + asserts: true # Check for plain error comparisons. - comparison: false + comparison: true exhaustive: default-signifies-exhaustive: true diff --git a/internal/chart/v3/lint/rules/deprecations_test.go b/internal/chart/v3/lint/rules/deprecations_test.go index a255abf50..55c454118 100644 --- a/internal/chart/v3/lint/rules/deprecations_test.go +++ b/internal/chart/v3/lint/rules/deprecations_test.go @@ -29,14 +29,12 @@ func TestValidateNoDeprecations(t *testing.T) { Kind: "Deployment", } err := validateNoDeprecations(deprecated, nil) - var depErr deprecatedAPIError require.Error(t, err, "Expected deprecated extension to be flagged") + var depErr deprecatedAPIError require.ErrorAs(t, err, &depErr, "Expected error to be of type deprecatedAPIError") require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank: %v", err) - - err = validateNoDeprecations(&k8sYamlStruct{ + assert.NoError(t, validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", - }, nil) - assert.NoError(t, err, "Expected a v1 Pod to not be deprecated") + }, nil), "Expected a v1 Pod to not be deprecated") } diff --git a/internal/plugin/runtime_subprocess.go b/internal/plugin/runtime_subprocess.go index b921587c1..2dbe220d9 100644 --- a/internal/plugin/runtime_subprocess.go +++ b/internal/plugin/runtime_subprocess.go @@ -18,6 +18,7 @@ package plugin import ( "bytes" "context" + "errors" "fmt" "io" "log/slog" @@ -152,7 +153,8 @@ func (r *SubprocessPluginRuntime) InvokeHook(event string) error { slog.Debug("executing plugin hook command", slog.String("pluginName", r.metadata.Name), slog.String("command", cmd.String())) if err := cmd.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { + var eerr *exec.ExitError + if errors.As(err, &eerr) { os.Stderr.Write(eerr.Stderr) return fmt.Errorf("plugin %s hook for %q exited with error", event, r.metadata.Name) } @@ -166,7 +168,8 @@ func (r *SubprocessPluginRuntime) InvokeHook(event string) error { // then replace the other three with a call to this func func executeCmd(prog *exec.Cmd, pluginName string) error { if err := prog.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { + var eerr *exec.ExitError + if errors.As(err, &eerr) { slog.Debug( "plugin execution failed", slog.String("pluginName", pluginName), diff --git a/internal/sympath/walk.go b/internal/sympath/walk.go index 812bb68ce..b54b97ad4 100644 --- a/internal/sympath/walk.go +++ b/internal/sympath/walk.go @@ -21,6 +21,7 @@ limitations under the License. package sympath import ( + "errors" "fmt" "log/slog" "os" @@ -40,7 +41,7 @@ func Walk(root string, walkFn filepath.WalkFunc) error { } else { err = symwalk(root, info, walkFn) } - if err == filepath.SkipDir { + if errors.Is(err, filepath.SkipDir) { return nil } return err @@ -75,7 +76,7 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { if info, err = os.Lstat(resolved); err != nil { return err } - if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir { + if err := symwalk(path, info, walkFn); err != nil && !errors.Is(err, filepath.SkipDir) { return err } return nil @@ -98,13 +99,13 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { filename := filepath.Join(path, name) fileInfo, err := os.Lstat(filename) if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { + if err := walkFn(filename, fileInfo, err); err != nil && !errors.Is(err, filepath.SkipDir) { return err } } else { err = symwalk(filename, fileInfo, walkFn) if err != nil { - if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { + if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || !errors.Is(err, filepath.SkipDir) { return err } } diff --git a/pkg/chart/v2/lint/rules/deprecations_test.go b/pkg/chart/v2/lint/rules/deprecations_test.go index 86643f1c9..fdeb47e91 100644 --- a/pkg/chart/v2/lint/rules/deprecations_test.go +++ b/pkg/chart/v2/lint/rules/deprecations_test.go @@ -16,7 +16,11 @@ limitations under the License. package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/require" +) func TestValidateNoDeprecations(t *testing.T) { deprecated := &k8sYamlStruct{ @@ -27,10 +31,9 @@ func TestValidateNoDeprecations(t *testing.T) { if err == nil { t.Fatal("Expected deprecated extension to be flagged") } - depErr := err.(deprecatedAPIError) - if depErr.Message == "" { - t.Fatalf("Expected error message to be non-blank: %v", err) - } + var depErr deprecatedAPIError + require.ErrorAs(t, err, &depErr) + require.NotEmptyf(t, depErr.Message, "Expected error message to be non-blank") if err := validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index f0eb008b3..12eec7531 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -24,6 +24,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" @@ -235,10 +238,9 @@ func TestDeprecatedAPIFails(t *testing.T) { t.Fatalf("Expected 1 lint error, got %d", l) } - err := linter.Messages[0].Err.(deprecatedAPIError) - if err.Deprecated != "apps/v1beta1 Deployment" { - t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) - } + var depErr deprecatedAPIError + require.ErrorAs(t, linter.Messages[0].Err, &depErr) + assert.Equalf(t, "apps/v1beta1 Deployment", depErr.Deprecated, "Surprised to learn that %q is deprecated", depErr.Deprecated) } const manifest = `apiVersion: v1 diff --git a/pkg/chart/v2/util/dependencies_test.go b/pkg/chart/v2/util/dependencies_test.go index 90a8806ec..40a17ac3a 100644 --- a/pkg/chart/v2/util/dependencies_test.go +++ b/pkg/chart/v2/util/dependencies_test.go @@ -21,6 +21,8 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -251,12 +253,8 @@ func TestProcessDependencyImportValues(t *testing.T) { if err == nil { t.Error("expect nil value not found but found it") } - switch xerr := err.(type) { - case common.ErrNoValue: - // We found what we expected - default: - t.Errorf("expected an ErrNoValue but got %q instead", xerr) - } + var xerr common.ErrNoValue + require.ErrorAs(t, err, &xerr, "expected an ErrNoValue") c = loadChart(t, "testdata/subpop") if err := processDependencyImportValues(c, true); err != nil { diff --git a/pkg/cmd/plugin_test.go b/pkg/cmd/plugin_test.go index 476997110..5364423a0 100644 --- a/pkg/cmd/plugin_test.go +++ b/pkg/cmd/plugin_test.go @@ -144,16 +144,10 @@ func TestLoadCLIPlugins(t *testing.T) { // tests until this is fixed if runtime.GOOS != "windows" { if err := pluginCmd.RunE(pluginCmd, tt.args); err != nil { - if tt.code > 0 { - cerr, ok := err.(CommandError) - if !ok { - t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err) - } - if cerr.ExitCode != tt.code { - t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) - } - } else { - t.Errorf("Error running %s: %+v", tt.use, err) + if assert.Positive(t, tt.code, "Error running %s: %+v", tt.use, err) { + var cerr CommandError + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err) + assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } assert.Equal(t, tt.expect, out.String(), "expected output for %q", tt.use) @@ -218,16 +212,10 @@ func TestLoadPluginsWithSpace(t *testing.T) { // tests until this is fixed if runtime.GOOS != "windows" { if err := pp.RunE(pp, tt.args); err != nil { - if tt.code > 0 { - cerr, ok := err.(CommandError) - if !ok { - t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err) - } - if cerr.ExitCode != tt.code { - t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) - } - } else { - t.Errorf("Error running %s: %+v", tt.use, err) + if assert.Positive(t, tt.code, "Error running %s: %+v", tt.use, err) { + var cerr CommandError + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err) + assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } assert.Equal(t, tt.expect, out.String(), "expected output for %s", tt.use) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index e363fad61..1dfa88800 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -249,7 +249,7 @@ func (c *Client) getKubeClient() (kubernetes.Interface, error) { // IsReachable tests connectivity to the cluster. func (c *Client) IsReachable() error { client, err := c.getKubeClient() - if err == genericclioptions.ErrEmptyConfig { + if errors.Is(err, genericclioptions.ErrEmptyConfig) { // re-replace kubernetes ErrEmptyConfig error with a friendly error // moar workarounds for Kubernetes API breaking. return errors.New("kubernetes cluster unreachable") @@ -949,11 +949,12 @@ func (c *Client) Delete(resources ResourceList, policy metav1.DeletionPropagatio func isIncompatibleServerError(err error) bool { // 415: Unsupported media type means we're talking to a server which doesn't // support server-side apply. - if _, ok := err.(*apierrors.StatusError); !ok { + var sErr *apierrors.StatusError + if !errors.As(err, &sErr) { // Non-StatusError means the error isn't because the server is incompatible. return false } - return err.(*apierrors.StatusError).Status().Code == http.StatusUnsupportedMediaType + return sErr.Status().Code == http.StatusUnsupportedMediaType } // isServerSideRetryable checks if an error encountered during server-side apply diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 3f8e654f9..79b33a970 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -385,11 +385,9 @@ func TestVerify(t *testing.T) { _, err = signer.Verify(archiveData, tamperedSigData, filepath.Base(testChartfile)) require.Errorf(t, err, "Expected %s to fail.", testTamperedSigBlock) - switch err.(type) { - case pgperrors.SignatureError: - t.Logf("Tampered sig block error: %s (%T)", err, err) - default: - t.Errorf("Expected invalid signature error, got %q (%T)", err, err) + var sErr pgperrors.SignatureError + if assert.ErrorAs(t, err, &sErr, "Expected invalid signature error, got %q (%T)", err, err) { + t.Logf("Tampered sig block error: %s (%T)", sErr, sErr) } } diff --git a/pkg/registry/transport.go b/pkg/registry/transport.go index beec43cdd..fa0103ac0 100644 --- a/pkg/registry/transport.go +++ b/pkg/registry/transport.go @@ -18,6 +18,7 @@ package registry import ( "bytes" + "errors" "fmt" "io" "log/slog" @@ -126,7 +127,7 @@ func logResponseBody(resp *http.Response) string { Closer: body, } // read the body up to limit+1 to check if the body exceeds the limit - if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && err != io.EOF { + if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && !errors.Is(err, io.EOF) { return fmt.Sprintf(" Error reading response body: %v", err) } diff --git a/pkg/repo/v1/index.go b/pkg/repo/v1/index.go index 839a4cca9..1c1497c5e 100644 --- a/pkg/repo/v1/index.go +++ b/pkg/repo/v1/index.go @@ -421,8 +421,8 @@ func jsonOrYamlUnmarshal(b []byte, i any) error { // And repository indexes may be generated by older/non-compliant software, which doesn't // conform to all validations. func ignoreSkippableChartValidationError(err error) error { - verr, ok := err.(chart.ValidationError) - if !ok { + var verr chart.ValidationError + if !errors.As(err, &verr) { return err } diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index d74e46986..be3b1e71b 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -238,16 +238,16 @@ func (t *parser) key(data map[string]any, nestedNameLevel int) (reterr error) { // End of key. Consume =, Get value. // FIXME: Get value list first vl, e := t.valList() - switch e { - case nil: + switch { + case e == nil: set(data, string(k), vl) return nil - case io.EOF: + case errors.Is(e, io.EOF): set(data, string(k), "") return e - case ErrNotList: + case errors.Is(e, ErrNotList): rs, e := t.val() - if e != nil && e != io.EOF { + if e != nil && !errors.Is(e, io.EOF) { return e } v, e := t.reader(rs) @@ -370,14 +370,14 @@ func (t *parser) listItem(list []any, i, nestedNameLevel int) ([]any, error) { return list, err } vl, e := t.valList() - switch e { - case nil: + switch { + case e == nil: return setIndex(list, i, vl) - case io.EOF: + case errors.Is(e, io.EOF): return setIndex(list, i, "") - case ErrNotList: + case errors.Is(e, ErrNotList): rs, e := t.val() - if e != nil && e != io.EOF { + if e != nil && !errors.Is(e, io.EOF) { return list, e } v, e := t.reader(rs) @@ -476,7 +476,7 @@ func (t *parser) valList() ([]any, error) { for { switch rs, last, err := runesUntil(t.sc, stop); { case err != nil: - if err == io.EOF { + if errors.Is(err, io.EOF) { err = errors.New("list must terminate with '}'") } return list, err From c2fda5ac5835cd1eca44a29047c18edcde66e00f Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Sat, 18 Jul 2026 05:33:34 -0600 Subject: [PATCH 082/161] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Terry Howe --- pkg/cli/environment_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index 2d7851a4f..fc71038f8 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -242,9 +242,7 @@ users: user: token: test-token ` - if err := os.WriteFile(kubeconfigPath, []byte(kubeconfig), 0o600); err != nil { - t.Fatalf("failed to create test kubeconfig: %v", err) - } + require.NoError(t, os.WriteFile(kubeconfigPath, []byte(kubeconfig), 0o600), "failed to create test kubeconfig") t.Setenv("KUBECONFIG", kubeconfigPath) settings := New() From 82be04d7f2881f59b3a85483eb248417e1d18fc3 Mon Sep 17 00:00:00 2001 From: Abhay Chaurasiya <44005156+abhay1999@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:12:20 +0530 Subject: [PATCH 083/161] remove legacy import comments from remaining packages (#31933) Pre-Go-modules import path comments (e.g. `// import "helm.sh/helm/v4/..."`) are obsolete since Go 1.11 where go.mod is the authoritative module path. These stale comments cause issues with downstream tooling such as Kythe. Removes the legacy import comments from 64 files across 20 packages: - cmd/helm - internal/chart/v3/lint and sub-packages - internal/plugin and sub-packages - internal/release/v2/util - pkg/chart/v2/lint and sub-packages - pkg/cmd, pkg/engine, pkg/ignore, pkg/provenance - pkg/registry - pkg/release/v1/util - pkg/repo/v1 - pkg/storage and pkg/storage/driver Follows up on #31931 and #31932 which addressed pkg/kube. Fixes #31846 Signed-off-by: abhay1999 Signed-off-by: abhay1999 --- cmd/helm/helm.go | 2 +- internal/chart/v3/lint/lint.go | 2 +- internal/chart/v3/lint/rules/chartfile.go | 2 +- internal/chart/v3/lint/rules/dependencies.go | 2 +- internal/chart/v3/lint/rules/deprecations.go | 2 +- internal/chart/v3/lint/rules/deprecations_test.go | 2 +- internal/chart/v3/lint/support/doc.go | 2 +- internal/plugin/cache/cache.go | 2 +- internal/plugin/installer/base.go | 2 +- internal/plugin/installer/base_test.go | 2 +- internal/plugin/installer/doc.go | 2 +- internal/plugin/installer/extractor.go | 2 +- internal/plugin/installer/http_installer.go | 2 +- internal/plugin/installer/http_installer_test.go | 2 +- internal/plugin/installer/local_installer.go | 2 +- internal/plugin/installer/local_installer_test.go | 2 +- internal/plugin/installer/oci_installer_test.go | 2 +- internal/plugin/installer/vcs_installer.go | 2 +- internal/plugin/installer/vcs_installer_test.go | 2 +- internal/plugin/plugin.go | 2 +- internal/plugin/runtime_subprocess_hooks.go | 2 +- internal/release/v2/util/filter.go | 2 +- internal/release/v2/util/filter_test.go | 2 +- internal/release/v2/util/kind_sorter.go | 2 +- internal/release/v2/util/kind_sorter_test.go | 2 +- internal/release/v2/util/manifest.go | 2 +- internal/release/v2/util/manifest_sorter.go | 2 +- internal/release/v2/util/manifest_sorter_test.go | 2 +- internal/release/v2/util/manifest_test.go | 2 +- internal/release/v2/util/sorter.go | 2 +- internal/release/v2/util/sorter_test.go | 2 +- pkg/chart/v2/lint/lint.go | 2 +- pkg/chart/v2/lint/rules/chartfile.go | 2 +- pkg/chart/v2/lint/rules/dependencies.go | 2 +- pkg/chart/v2/lint/rules/deprecations.go | 2 +- pkg/chart/v2/lint/rules/deprecations_test.go | 2 +- pkg/chart/v2/lint/support/doc.go | 2 +- pkg/cmd/root.go | 2 +- pkg/engine/doc.go | 2 +- pkg/ignore/doc.go | 2 +- pkg/provenance/doc.go | 2 +- pkg/registry/chart.go | 2 +- pkg/registry/chart_test.go | 2 +- pkg/registry/client.go | 2 +- pkg/registry/constants.go | 2 +- pkg/registry/tag.go | 2 +- pkg/release/v1/util/filter.go | 2 +- pkg/release/v1/util/filter_test.go | 2 +- pkg/release/v1/util/manifest_test.go | 2 +- pkg/release/v1/util/sorter.go | 2 +- pkg/release/v1/util/sorter_test.go | 2 +- pkg/repo/v1/chartrepo.go | 2 +- pkg/repo/v1/repo.go | 2 +- pkg/storage/driver/cfgmaps.go | 2 +- pkg/storage/driver/driver.go | 2 +- pkg/storage/driver/labels_test.go | 2 +- pkg/storage/driver/mock_test.go | 2 +- pkg/storage/driver/records.go | 2 +- pkg/storage/driver/records_test.go | 2 +- pkg/storage/driver/secrets.go | 2 +- pkg/storage/driver/sql.go | 2 +- pkg/storage/driver/util.go | 2 +- pkg/storage/storage.go | 2 +- pkg/storage/storage_test.go | 2 +- 64 files changed, 64 insertions(+), 64 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 0c4f697b6..60df8a308 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main // import "helm.sh/helm/v4/cmd/helm" +package main import ( "errors" diff --git a/internal/chart/v3/lint/lint.go b/internal/chart/v3/lint/lint.go index ea8ca3d60..193f0f796 100644 --- a/internal/chart/v3/lint/lint.go +++ b/internal/chart/v3/lint/lint.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package lint // import "helm.sh/helm/v4/internal/chart/v3/lint" +package lint import ( "path/filepath" diff --git a/internal/chart/v3/lint/rules/chartfile.go b/internal/chart/v3/lint/rules/chartfile.go index db7ac61dc..c76654d53 100644 --- a/internal/chart/v3/lint/rules/chartfile.go +++ b/internal/chart/v3/lint/rules/chartfile.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "errors" diff --git a/internal/chart/v3/lint/rules/dependencies.go b/internal/chart/v3/lint/rules/dependencies.go index f45153728..2f558aaf0 100644 --- a/internal/chart/v3/lint/rules/dependencies.go +++ b/internal/chart/v3/lint/rules/dependencies.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "fmt" diff --git a/internal/chart/v3/lint/rules/deprecations.go b/internal/chart/v3/lint/rules/deprecations.go index 9c73268af..85dddd114 100644 --- a/internal/chart/v3/lint/rules/deprecations.go +++ b/internal/chart/v3/lint/rules/deprecations.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "fmt" diff --git a/internal/chart/v3/lint/rules/deprecations_test.go b/internal/chart/v3/lint/rules/deprecations_test.go index 55c454118..920fdc31f 100644 --- a/internal/chart/v3/lint/rules/deprecations_test.go +++ b/internal/chart/v3/lint/rules/deprecations_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "testing" diff --git a/internal/chart/v3/lint/support/doc.go b/internal/chart/v3/lint/support/doc.go index 2d54a9b7d..80b1d2169 100644 --- a/internal/chart/v3/lint/support/doc.go +++ b/internal/chart/v3/lint/support/doc.go @@ -20,4 +20,4 @@ Package support contains tools for linting charts. Linting is the process of testing charts for errors or warnings regarding formatting, compilation, or standards compliance. */ -package support // import "helm.sh/helm/v4/internal/chart/v3/lint/support" +package support diff --git a/internal/plugin/cache/cache.go b/internal/plugin/cache/cache.go index f3b737477..1613d4d76 100644 --- a/internal/plugin/cache/cache.go +++ b/internal/plugin/cache/cache.go @@ -14,7 +14,7 @@ limitations under the License. */ // Package cache provides a key generator for vcs urls. -package cache // import "helm.sh/helm/v4/internal/plugin/cache" +package cache import ( "net/url" diff --git a/internal/plugin/installer/base.go b/internal/plugin/installer/base.go index c21a245a8..54d25287a 100644 --- a/internal/plugin/installer/base.go +++ b/internal/plugin/installer/base.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "path/filepath" diff --git a/internal/plugin/installer/base_test.go b/internal/plugin/installer/base_test.go index 6df8ec8a1..b7902e699 100644 --- a/internal/plugin/installer/base_test.go +++ b/internal/plugin/installer/base_test.go @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "testing" diff --git a/internal/plugin/installer/doc.go b/internal/plugin/installer/doc.go index a4cf384bf..a9d9555c9 100644 --- a/internal/plugin/installer/doc.go +++ b/internal/plugin/installer/doc.go @@ -14,4 +14,4 @@ limitations under the License. */ // Package installer provides an interface for installing Helm plugins. -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer diff --git a/internal/plugin/installer/extractor.go b/internal/plugin/installer/extractor.go index 85d695bd2..6cd45e2d8 100644 --- a/internal/plugin/installer/extractor.go +++ b/internal/plugin/installer/extractor.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" diff --git a/internal/plugin/installer/http_installer.go b/internal/plugin/installer/http_installer.go index 92d3d686e..7be326de2 100644 --- a/internal/plugin/installer/http_installer.go +++ b/internal/plugin/installer/http_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "bytes" diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index cbd868f3a..3235e9796 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" diff --git a/internal/plugin/installer/local_installer.go b/internal/plugin/installer/local_installer.go index a7a6caa14..59918401b 100644 --- a/internal/plugin/installer/local_installer.go +++ b/internal/plugin/installer/local_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "bytes" diff --git a/internal/plugin/installer/local_installer_test.go b/internal/plugin/installer/local_installer_test.go index 02d4d7bff..f46fcb44b 100644 --- a/internal/plugin/installer/local_installer_test.go +++ b/internal/plugin/installer/local_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" diff --git a/internal/plugin/installer/oci_installer_test.go b/internal/plugin/installer/oci_installer_test.go index c3bebdb52..48eccf6e1 100644 --- a/internal/plugin/installer/oci_installer_test.go +++ b/internal/plugin/installer/oci_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" diff --git a/internal/plugin/installer/vcs_installer.go b/internal/plugin/installer/vcs_installer.go index 3601ec7a8..13aba74dc 100644 --- a/internal/plugin/installer/vcs_installer.go +++ b/internal/plugin/installer/vcs_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "errors" diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 401f2b921..7e44cc957 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "fmt" diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 789e583ae..ad2dd7922 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package plugin // import "helm.sh/helm/v4/internal/plugin" +package plugin import ( "context" diff --git a/internal/plugin/runtime_subprocess_hooks.go b/internal/plugin/runtime_subprocess_hooks.go index 7b4ff5a38..8d5f3cba6 100644 --- a/internal/plugin/runtime_subprocess_hooks.go +++ b/internal/plugin/runtime_subprocess_hooks.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package plugin // import "helm.sh/helm/v4/internal/plugin" +package plugin // Types of hooks const ( diff --git a/internal/release/v2/util/filter.go b/internal/release/v2/util/filter.go index bc568cbdc..0daf06014 100644 --- a/internal/release/v2/util/filter.go +++ b/internal/release/v2/util/filter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( v2 "helm.sh/helm/v4/internal/release/v2" diff --git a/internal/release/v2/util/filter_test.go b/internal/release/v2/util/filter_test.go index 8c7363b87..542510ba3 100644 --- a/internal/release/v2/util/filter_test.go +++ b/internal/release/v2/util/filter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/release/v2/util/kind_sorter.go b/internal/release/v2/util/kind_sorter.go index dba35b6d2..950e836fa 100644 --- a/internal/release/v2/util/kind_sorter.go +++ b/internal/release/v2/util/kind_sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "sort" diff --git a/internal/release/v2/util/kind_sorter_test.go b/internal/release/v2/util/kind_sorter_test.go index dba19e287..06885aa93 100644 --- a/internal/release/v2/util/kind_sorter_test.go +++ b/internal/release/v2/util/kind_sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "bytes" diff --git a/internal/release/v2/util/manifest.go b/internal/release/v2/util/manifest.go index d3296984e..37b9dfbd3 100644 --- a/internal/release/v2/util/manifest.go +++ b/internal/release/v2/util/manifest.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "fmt" diff --git a/internal/release/v2/util/manifest_sorter.go b/internal/release/v2/util/manifest_sorter.go index f269dda6d..3507deed5 100644 --- a/internal/release/v2/util/manifest_sorter.go +++ b/internal/release/v2/util/manifest_sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "fmt" diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index eac9c9f36..deb9426ce 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/release/v2/util/manifest_test.go b/internal/release/v2/util/manifest_test.go index 1806368af..e76905a63 100644 --- a/internal/release/v2/util/manifest_test.go +++ b/internal/release/v2/util/manifest_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/release/v2/util/sorter.go b/internal/release/v2/util/sorter.go index 5f13569c1..66b51d873 100644 --- a/internal/release/v2/util/sorter.go +++ b/internal/release/v2/util/sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "sort" diff --git a/internal/release/v2/util/sorter_test.go b/internal/release/v2/util/sorter_test.go index 82a53ae66..e151f0790 100644 --- a/internal/release/v2/util/sorter_test.go +++ b/internal/release/v2/util/sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/pkg/chart/v2/lint/lint.go b/pkg/chart/v2/lint/lint.go index 23a93c551..204c15861 100644 --- a/pkg/chart/v2/lint/lint.go +++ b/pkg/chart/v2/lint/lint.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package lint // import "helm.sh/helm/v4/pkg/chart/v2/lint" +package lint import ( "path/filepath" diff --git a/pkg/chart/v2/lint/rules/chartfile.go b/pkg/chart/v2/lint/rules/chartfile.go index 08508f46e..f867daa21 100644 --- a/pkg/chart/v2/lint/rules/chartfile.go +++ b/pkg/chart/v2/lint/rules/chartfile.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "errors" diff --git a/pkg/chart/v2/lint/rules/dependencies.go b/pkg/chart/v2/lint/rules/dependencies.go index d944a016d..616984c08 100644 --- a/pkg/chart/v2/lint/rules/dependencies.go +++ b/pkg/chart/v2/lint/rules/dependencies.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "fmt" diff --git a/pkg/chart/v2/lint/rules/deprecations.go b/pkg/chart/v2/lint/rules/deprecations.go index 76626659b..2ed682891 100644 --- a/pkg/chart/v2/lint/rules/deprecations.go +++ b/pkg/chart/v2/lint/rules/deprecations.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "fmt" diff --git a/pkg/chart/v2/lint/rules/deprecations_test.go b/pkg/chart/v2/lint/rules/deprecations_test.go index fdeb47e91..0aa983678 100644 --- a/pkg/chart/v2/lint/rules/deprecations_test.go +++ b/pkg/chart/v2/lint/rules/deprecations_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "testing" diff --git a/pkg/chart/v2/lint/support/doc.go b/pkg/chart/v2/lint/support/doc.go index 7e050b8c2..80b1d2169 100644 --- a/pkg/chart/v2/lint/support/doc.go +++ b/pkg/chart/v2/lint/support/doc.go @@ -20,4 +20,4 @@ Package support contains tools for linting charts. Linting is the process of testing charts for errors or warnings regarding formatting, compilation, or standards compliance. */ -package support // import "helm.sh/helm/v4/pkg/chart/v2/lint/support" +package support diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 28798de5c..410a9162c 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cmd // import "helm.sh/helm/v4/pkg/cmd" +package cmd import ( "context" diff --git a/pkg/engine/doc.go b/pkg/engine/doc.go index e764a829a..9bb1059f2 100644 --- a/pkg/engine/doc.go +++ b/pkg/engine/doc.go @@ -21,4 +21,4 @@ When Helm renders templates it does so with additional functions and different modes (e.g., strict, lint mode). This package handles the helm specific implementation. */ -package engine // import "helm.sh/helm/v4/pkg/engine" +package engine diff --git a/pkg/ignore/doc.go b/pkg/ignore/doc.go index a66066eb2..bba658d41 100644 --- a/pkg/ignore/doc.go +++ b/pkg/ignore/doc.go @@ -65,4 +65,4 @@ Notable differences from .gitignore: - The evaluation of escape sequences has not been tested for compatibility - There is no support for '\!' as a special leading sequence. */ -package ignore // import "helm.sh/helm/v4/pkg/ignore" +package ignore diff --git a/pkg/provenance/doc.go b/pkg/provenance/doc.go index dd14568d9..bd60bc593 100644 --- a/pkg/provenance/doc.go +++ b/pkg/provenance/doc.go @@ -35,4 +35,4 @@ and using `gpg --verify`, `keybase pgp verify`, or similar: gpg: Signature made Mon Jul 25 17:23:44 2016 MDT using RSA key ID 1FC18762 gpg: Good signature from "Helm Testing (This key should only be used for testing. DO NOT TRUST.) " [ultimate] */ -package provenance // import "helm.sh/helm/v4/pkg/provenance" +package provenance diff --git a/pkg/registry/chart.go b/pkg/registry/chart.go index 7c41785c5..b8b0d88b6 100644 --- a/pkg/registry/chart.go +++ b/pkg/registry/chart.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "bytes" diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index e27c3d619..c80544b5b 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "testing" diff --git a/pkg/registry/client.go b/pkg/registry/client.go index cba346dea..d1a744f4b 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "context" diff --git a/pkg/registry/constants.go b/pkg/registry/constants.go index c455cf314..df31a18c4 100644 --- a/pkg/registry/constants.go +++ b/pkg/registry/constants.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry const ( // OCIScheme is the URL scheme for OCI-based requests diff --git a/pkg/registry/tag.go b/pkg/registry/tag.go index bfb4b1ef6..7e15d0dd9 100644 --- a/pkg/registry/tag.go +++ b/pkg/registry/tag.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "fmt" diff --git a/pkg/release/v1/util/filter.go b/pkg/release/v1/util/filter.go index dc60195cf..88ac995d7 100644 --- a/pkg/release/v1/util/filter.go +++ b/pkg/release/v1/util/filter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "helm.sh/helm/v4/pkg/release/common" diff --git a/pkg/release/v1/util/filter_test.go b/pkg/release/v1/util/filter_test.go index d6bda8f84..57d7e6801 100644 --- a/pkg/release/v1/util/filter_test.go +++ b/pkg/release/v1/util/filter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/release/v1/util/manifest_test.go b/pkg/release/v1/util/manifest_test.go index 773723c86..e76905a63 100644 --- a/pkg/release/v1/util/manifest_test.go +++ b/pkg/release/v1/util/manifest_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/release/v1/util/sorter.go b/pkg/release/v1/util/sorter.go index 47506fbf2..e15b87593 100644 --- a/pkg/release/v1/util/sorter.go +++ b/pkg/release/v1/util/sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "sort" diff --git a/pkg/release/v1/util/sorter_test.go b/pkg/release/v1/util/sorter_test.go index 0450b09e6..1a3bb3e6a 100644 --- a/pkg/release/v1/util/sorter_test.go +++ b/pkg/release/v1/util/sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/repo/v1/chartrepo.go b/pkg/repo/v1/chartrepo.go index c7c4a3e7b..42ed52f75 100644 --- a/pkg/repo/v1/chartrepo.go +++ b/pkg/repo/v1/chartrepo.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package repo // import "helm.sh/helm/v4/pkg/repo/v1" +package repo import ( "bytes" diff --git a/pkg/repo/v1/repo.go b/pkg/repo/v1/repo.go index 199b56ed8..be241a0ab 100644 --- a/pkg/repo/v1/repo.go +++ b/pkg/repo/v1/repo.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package repo // import "helm.sh/helm/v4/pkg/repo/v1" +package repo import ( "fmt" diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 2636755a9..f71ce44f1 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" diff --git a/pkg/storage/driver/driver.go b/pkg/storage/driver/driver.go index 6efd1dbaa..a7d194d69 100644 --- a/pkg/storage/driver/driver.go +++ b/pkg/storage/driver/driver.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "errors" diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index 81e561c15..848ae8861 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "testing" diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index e62b02f43..ab7b261cf 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" diff --git a/pkg/storage/driver/records.go b/pkg/storage/driver/records.go index 6b4efef3a..f78b76b8b 100644 --- a/pkg/storage/driver/records.go +++ b/pkg/storage/driver/records.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "sort" diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 24e4ccb4e..cd1064342 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "reflect" diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 5e12684df..a1f3e94fc 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index 88d24123d..85e6cbd3f 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "fmt" diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index 4bc48db23..08c38585c 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "bytes" diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index d5d2ea317..1d7fb9103 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package storage // import "helm.sh/helm/v4/pkg/storage" +package storage import ( "errors" diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 32f926e08..8ecee447f 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package storage // import "helm.sh/helm/v4/pkg/storage" +package storage import ( "context" From 3bcf965f997499c477436515e6ccf5d51ab82e5e Mon Sep 17 00:00:00 2001 From: Zhaofeng Miao <522856232@qq.com> Date: Sat, 18 Jul 2026 21:10:36 +0800 Subject: [PATCH 084/161] perf: enable concurrent status computation to prevent multi-minute delays (#32043) * fix: enable concurrent status computation to prevent multi-minute delays Set StatusComputeWorkers=8 on DefaultStatusWatcher for Wait, WaitWithJobs, and WatchUntilReady. This opts in to the async status computation added in fluxcd/cli-utils#20, preventing the informer notification pipeline from being blocked by slow API calls when many resources are updated simultaneously. Without this, status computation for resources like Deployments (which require additional LIST ReplicaSets/Pods calls) runs serially inside the informer, causing growing delays of 1-3+ minutes when upgrading many resources at once (e.g., ~20 Deployments via Helm). Signed-off-by: maplemiao * refactor(kube): expose StatusComputeWorkers as a WaitOption Replace the package-level DefaultStatusComputeWorkers variable with a WithStatusComputeWorkers WaitOption threaded through waitOptions into the statusWaiter. This removes global mutable state from pkg/kube and lets callers opt in explicitly. SDK consumers (e.g. helm-controller) inherit the zero value, which preserves the upstream cli-utils synchronous behavior and avoids an unexpected fan-out of status-compute goroutines when many releases reconcile concurrently. The Helm CLI continues to enable 8 workers by default via a shared pkg/cmd/flags.go helper, so install/upgrade/ rollback/uninstall/test users still get the fix for multi-minute informer stalls out of the box. Signed-off-by: maplemiao * refactor(kube): clamp negative StatusComputeWorkers values to zero Address review feedback: when a caller passes a negative value to WithStatusComputeWorkers, coerce it to zero rather than propagating it to the underlying cli-utils watcher, where the behavior is undefined. Zero is the safe default and matches the SDK opt-in contract. Signed-off-by: maplemiao --------- Signed-off-by: maplemiao Signed-off-by: Maple Miao Co-authored-by: Cursor --- pkg/cmd/flags.go | 20 ++++++++++++++++++++ pkg/cmd/install.go | 1 + pkg/cmd/release_testing.go | 1 + pkg/cmd/rollback.go | 1 + pkg/cmd/uninstall.go | 1 + pkg/cmd/upgrade.go | 2 ++ pkg/kube/client.go | 17 +++++++++-------- pkg/kube/options.go | 35 +++++++++++++++++++++++++++++------ pkg/kube/statuswait.go | 20 ++++++++++++-------- pkg/kube/statuswait_test.go | 22 ++++++++++++++++++++++ 10 files changed, 98 insertions(+), 22 deletions(-) diff --git a/pkg/cmd/flags.go b/pkg/cmd/flags.go index e7db3dde2..e59487044 100644 --- a/pkg/cmd/flags.go +++ b/pkg/cmd/flags.go @@ -65,6 +65,26 @@ func AddWaitFlag(cmd *cobra.Command, wait *kube.WaitStrategy) { cmd.Flags().Lookup("wait").NoOptDefVal = string(kube.StatusWatcherStrategy) } +// cliDefaultStatusComputeWorkers is the number of concurrent status-compute +// workers the Helm CLI enables by default. This prevents the informer +// notification pipeline from being blocked by slow API calls (e.g. LIST +// ReplicaSets/Pods for Deployments) when many resources are updated +// simultaneously. See https://github.com/fluxcd/cli-utils/pull/20. +// +// SDK consumers (e.g. helm-controller) inherit the zero value and can opt in +// via kube.WithStatusComputeWorkers when they want the same behavior. +const cliDefaultStatusComputeWorkers = 8 + +// defaultCLIWaitOptions returns the set of WaitOptions the Helm CLI applies +// by default to every wait-enabled command. Keeping these in one place keeps +// behavior consistent across install/upgrade/rollback/uninstall and makes the +// CLI-vs-SDK default asymmetry explicit. +func defaultCLIWaitOptions() []kube.WaitOption { + return []kube.WaitOption{ + kube.WithStatusComputeWorkers(cliDefaultStatusComputeWorkers), + } +} + type waitValue kube.WaitStrategy func newWaitValue(defaultValue kube.WaitStrategy, ws *kube.WaitStrategy) *waitValue { diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index b935ed4d0..b6cee5843 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -131,6 +131,7 @@ charts in a repository, use 'helm search'. func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewInstall(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) valueOpts := &values.Options{} var outfmt output.Format diff --git a/pkg/cmd/release_testing.go b/pkg/cmd/release_testing.go index 5a6159e7d..6be83c966 100644 --- a/pkg/cmd/release_testing.go +++ b/pkg/cmd/release_testing.go @@ -40,6 +40,7 @@ The tests to be run are defined in the chart that was installed. func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewReleaseTesting(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) outfmt := output.Table var outputLogs bool var filter []string diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 01d8b1866..b716dae10 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -40,6 +40,7 @@ To see revision numbers, run 'helm history RELEASE'. func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewRollback(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) cmd := &cobra.Command{ Use: "rollback [REVISION]", diff --git a/pkg/cmd/uninstall.go b/pkg/cmd/uninstall.go index bfecd4741..315c29a8d 100644 --- a/pkg/cmd/uninstall.go +++ b/pkg/cmd/uninstall.go @@ -42,6 +42,7 @@ are fully deleted before the command returns. func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewUninstall(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) cmd := &cobra.Command{ Use: "uninstall RELEASE_NAME [...]", diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index c038a2149..d0d0166ba 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -84,6 +84,7 @@ which can contain sensitive values. To hide Kubernetes Secrets use the func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewUpgrade(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) valueOpts := &values.Options{} var outfmt output.Format var createNamespace bool @@ -139,6 +140,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.SkipCRDs = client.SkipCRDs instClient.Timeout = client.Timeout instClient.WaitStrategy = client.WaitStrategy + instClient.WaitOptions = client.WaitOptions instClient.WaitForJobs = client.WaitForJobs instClient.Devel = client.Devel instClient.Namespace = client.Namespace diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 1dfa88800..bb26fbcc9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -167,14 +167,15 @@ func (c *Client) newStatusWatcher(opts ...WaitOption) (*statusWaiter, error) { waitContext = c.WaitContext } sw := &statusWaiter{ - restMapper: restMapper, - client: dynamicClient, - ctx: waitContext, - watchUntilReadyCtx: o.watchUntilReadyCtx, - waitCtx: o.waitCtx, - waitWithJobsCtx: o.waitWithJobsCtx, - waitForDeleteCtx: o.waitForDeleteCtx, - readers: o.statusReaders, + restMapper: restMapper, + client: dynamicClient, + ctx: waitContext, + watchUntilReadyCtx: o.watchUntilReadyCtx, + waitCtx: o.waitCtx, + waitWithJobsCtx: o.waitWithJobsCtx, + waitForDeleteCtx: o.waitForDeleteCtx, + readers: o.statusReaders, + statusComputeWorkers: o.statusComputeWorkers, } sw.SetLogger(c.Logger().Handler()) return sw, nil diff --git a/pkg/kube/options.go b/pkg/kube/options.go index 3326c284b..7853cb63a 100644 --- a/pkg/kube/options.go +++ b/pkg/kube/options.go @@ -72,11 +72,34 @@ func WithKStatusReaders(readers ...engine.StatusReader) WaitOption { } } +// WithStatusComputeWorkers sets the number of concurrent goroutines used to +// compute object status per informer. This prevents the informer notification +// pipeline from being blocked by slow API calls (e.g., LIST ReplicaSets/Pods +// for Deployments) when many resources are updated simultaneously. +// +// A value of 0 (the default) keeps the underlying cli-utils behavior, where +// status is computed synchronously on the informer goroutine. Negative values +// are clamped to 0 so callers cannot propagate invalid counts to the +// underlying watcher. SDK consumers (for example helm-controller) inherit +// this conservative default and can opt in explicitly. The Helm CLI passes +// a non-zero value so that `helm install/upgrade/rollback` users get the +// fix for multi-minute waits out of the box. +// See https://github.com/fluxcd/cli-utils/pull/20. +func WithStatusComputeWorkers(n int) WaitOption { + return func(wo *waitOptions) { + if n < 0 { + n = 0 + } + wo.statusComputeWorkers = n + } +} + type waitOptions struct { - ctx context.Context - watchUntilReadyCtx context.Context - waitCtx context.Context - waitWithJobsCtx context.Context - waitForDeleteCtx context.Context - statusReaders []engine.StatusReader + ctx context.Context + watchUntilReadyCtx context.Context + waitCtx context.Context + waitWithJobsCtx context.Context + waitForDeleteCtx context.Context + statusReaders []engine.StatusReader + statusComputeWorkers int } diff --git a/pkg/kube/statuswait.go b/pkg/kube/statuswait.go index 12c3e95a6..91eec30ef 100644 --- a/pkg/kube/statuswait.go +++ b/pkg/kube/statuswait.go @@ -43,14 +43,15 @@ import ( ) type statusWaiter struct { - client dynamic.Interface - restMapper meta.RESTMapper - ctx context.Context - watchUntilReadyCtx context.Context - waitCtx context.Context - waitWithJobsCtx context.Context - waitForDeleteCtx context.Context - readers []engine.StatusReader + client dynamic.Interface + restMapper meta.RESTMapper + ctx context.Context + watchUntilReadyCtx context.Context + waitCtx context.Context + waitWithJobsCtx context.Context + waitForDeleteCtx context.Context + readers []engine.StatusReader + statusComputeWorkers int logging.LogHolder } @@ -82,6 +83,7 @@ func (w *statusWaiter) WatchUntilReady(resourceList ResourceList, timeout time.D defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers jobSR := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) podSR := helmStatusReaders.NewCustomPodStatusReader(w.restMapper) // We don't want to wait on any other resources as watchUntilReady is only for Helm hooks. @@ -104,6 +106,7 @@ func (w *statusWaiter) Wait(resourceList ResourceList, timeout time.Duration) er defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers sw.StatusReader = statusreaders.NewStatusReader(w.restMapper, w.readers...) return w.wait(ctx, resourceList, sw) } @@ -116,6 +119,7 @@ func (w *statusWaiter) WaitWithJobs(resourceList ResourceList, timeout time.Dura defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers newCustomJobStatusReader := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) readers := append([]engine.StatusReader(nil), w.readers...) readers = append(readers, newCustomJobStatusReader) diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 14f10124c..21580b57a 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -1293,6 +1293,28 @@ func TestWaitOptionFunctions(t *testing.T) { WithWaitForDeleteMethodContext(ctx)(opts) assert.Equal(t, ctx, opts.waitForDeleteCtx) }) + + t.Run("WithStatusComputeWorkers sets statusComputeWorkers", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + WithStatusComputeWorkers(8)(opts) + assert.Equal(t, 8, opts.statusComputeWorkers) + }) + + t.Run("WithStatusComputeWorkers clamps negative values to zero", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + WithStatusComputeWorkers(-1)(opts) + assert.Equal(t, 0, opts.statusComputeWorkers, + "negative worker counts must not propagate to the underlying watcher") + }) + + t.Run("waitOptions.statusComputeWorkers defaults to zero", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + assert.Equal(t, 0, opts.statusComputeWorkers, + "SDK consumers must opt in to concurrent status computation") + }) } func TestMethodSpecificContextCancellation(t *testing.T) { From 0604d8fb1ee8ea172604cb739c93ea8d5ad068c6 Mon Sep 17 00:00:00 2001 From: Gates Wang <9372086+SetagGnaw@users.noreply.github.com> Date: Sun, 19 Jul 2026 20:36:57 -0400 Subject: [PATCH 085/161] fix: pass registry client to downloader.Manager in upgrade `helm upgrade --dependency-update` built its downloader.Manager without a RegistryClient, unlike the identical literals in install, dependency update, and dependency build. Resolving an OCI chart dependency whose version is a range then dereferenced a nil *registry.Client in registry.(*Client).Tags, panicking the process. Pass the registry client already constructed for the command, matching install. Add a regression test that runs `upgrade --dependency-update` against a chart with an unresolved OCI dependency and asserts the command returns an error instead of panicking. Signed-off-by: Gates Wang <9372086+SetagGnaw@users.noreply.github.com> --- pkg/cmd/upgrade.go | 1 + pkg/cmd/upgrade_test.go | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index d0d0166ba..688842141 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -226,6 +226,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { ContentCache: settings.ContentCache, Debug: settings.Debug, SourceDateEpoch: sourceDateEpoch, + RegistryClient: registryClient, } if err := man.Update(); err != nil { return err diff --git a/pkg/cmd/upgrade_test.go b/pkg/cmd/upgrade_test.go index 30188d3d9..203ec19cc 100644 --- a/pkg/cmd/upgrade_test.go +++ b/pkg/cmd/upgrade_test.go @@ -18,6 +18,8 @@ package cmd import ( "fmt" + "net/http" + "net/http/httptest" "os" "path/filepath" "reflect" @@ -193,6 +195,64 @@ func TestUpgradeCmd(t *testing.T) { runTestCmd(t, tests) } +// TestUpgradeDependencyUpdateOCINoPanic is a regression test for a nil-pointer +// panic in `helm upgrade --dependency-update` when a chart declares an OCI +// dependency. The upgrade command built its downloader.Manager without a +// RegistryClient (unlike install, dependency update, and dependency build), so +// resolving an OCI dependency dereferenced a nil *registry.Client. The command +// must now return a graceful error instead of panicking. +func TestUpgradeDependencyUpdateOCINoPanic(t *testing.T) { + defer resetEnv()() + + // A stub registry that answers the API-version ping but rejects the tag + // lookup, so OCI dependency resolution fails fast and hermetically instead + // of reaching a real registry. + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Docker-Distribution-API-Version", "registry/2.0") + if r.URL.Path == "/v2/" { + w.WriteHeader(http.StatusOK) + return + } + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + // A chart with an unresolved OCI dependency forces --dependency-update into + // the tag-lookup path that previously panicked: the version is a range (an + // explicit version would skip the lookup) and the dependency is not present + // under charts/. + tmp := t.TempDir() + parent := &chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: chart.APIVersionV2, + Name: "oci-parent", + Version: "0.1.0", + Dependencies: []*chart.Dependency{{ + Name: "subchart", + Repository: fmt.Sprintf("oci://%s/charts", srv.Listener.Addr()), + Version: "^1.0.0", + }}, + }, + } + if err := chartutil.SaveDir(parent, tmp); err != nil { + t.Fatalf("Error creating chart: %v", err) + } + chartPath := filepath.Join(tmp, parent.Metadata.Name) + // SaveDir writes only resolved subcharts (Chart.Dependencies()), not the + // declared Metadata.Dependencies, so create the empty charts/ directory + // explicitly to make the "dependency missing from charts/" state concrete. + if err := os.MkdirAll(filepath.Join(chartPath, "charts"), 0o755); err != nil { + t.Fatalf("Error creating charts dir: %v", err) + } + + // The command must return an error (registry rejects the lookup), not panic. + _, _, err := executeActionCommandC(storageFixture(), + fmt.Sprintf("upgrade --dependency-update --plain-http oci-parent '%s'", chartPath)) + if err == nil { + t.Fatal("expected an error resolving the OCI dependency, got nil") + } +} + func TestUpgradeWithValue(t *testing.T) { releaseName := "funny-bunny-v2" relMock, ch, chartPath := prepareMockRelease(t, releaseName) From 615a29987660b11909f984887b47f7f608757d87 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 086/161] chore(internal): refactor: convert tests to testify assert/require part 2 #### Description refactor: convert tests to testify assert/require in internal/plugin/installer Signed-off-by: Matthieu MOREL --- internal/chart/v3/util/dependencies_test.go | 12 +- .../plugin/installer/http_installer_test.go | 290 ++++++------------ .../plugin/installer/local_installer_test.go | 80 ++--- 3 files changed, 116 insertions(+), 266 deletions(-) diff --git a/internal/chart/v3/util/dependencies_test.go b/internal/chart/v3/util/dependencies_test.go index f6ca06da3..45693ef46 100644 --- a/internal/chart/v3/util/dependencies_test.go +++ b/internal/chart/v3/util/dependencies_test.go @@ -369,8 +369,7 @@ func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - err := processDependencyEnabled(c, c.Values, "") - require.NoError(t, err, "expected no errors") + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") } @@ -381,8 +380,7 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { func TestDependentChartsWithSubChartsSymlink(t *testing.T) { joonix := filepath.Join("testdata", "joonix") - err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")) - require.NoError(t, err, "failed to create symlink") + require.NoError(t, os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")), "failed to create symlink") defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) c := loadChart(t, joonix) @@ -394,12 +392,8 @@ func TestDependentChartsWithSubchartsAllSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-all-in-requirements-yaml") require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - - err := processDependencyEnabled(c, c.Values, "") - require.NoError(t, err, "expected no errors") - + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") - require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) } diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index 3235e9796..d0d5e099d 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -27,10 +27,14 @@ import ( "net/http/httptest" "os" "path/filepath" + "strconv" "strings" "syscall" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/helmpath" @@ -52,18 +56,10 @@ func (t *TestHTTPGetter) Get(_ string, _ ...getter.Option) (*bytes.Buffer, error var fakePluginB64 = "H4sIAAAAAAAAA+3SQUvDMBgG4Jz7K0LwapdvSxrwJig6mCKC5xHabBaXdDSt4L+3cQ56mV42ZPg+lw+SF5LwZmXf3OV206/rMGEnIgdG6zTJaDmee4y01FOlZpqGHJGZSsb1qS401sfOtpyz0FTup9xv+2dqNep/N/IP6zdHPSMVXCh1sH8yhtGMDBUFFTL1r4iIcXnUWxzwz/sP1rsrLkbfQGTvro11E4ZlmcucRNZHu04py1OO73OVi2Vbb7td9vp7nXevtvsKRpGVjfc2VMP2xf3t4mH5tHi5mz8ub+bPk9JXIvvr5wMAAAAAAAAAAAAAAAAAAAAAnLVPqwHcXQAoAAA=" func TestStripName(t *testing.T) { - if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin.tgz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { - t.Error("name does not match expected value") - } + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin-0.0.1.tar.gz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin-0.0.1.tgz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin.tgz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin.tar.gz"), "name does not match expected value") } func mockArchiveServer() *httptest.Server { @@ -85,45 +81,29 @@ func TestHTTPInstaller(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.1") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with minimal plugin tarball mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) - if err != nil { - t.Fatalf("Could not decode fake tgz plugin: %s", err) - } + require.NoError(t, err, "Could not decode fake tgz plugin") httpInstaller.getter = &TestHTTPGetter{ MockResponse: bytes.NewBuffer(mockTgz), } // install the plugin - if err := Install(i); err != nil { - t.Fatal(err) - } - if i.Path() != helmpath.DataPath("plugins", "fake-plugin") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) - } + require.NoError(t, Install(i)) + require.Equal(t, helmpath.DataPath("plugins", "fake-plugin"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) // Install again to test plugin exists error - if err := Install(i); err == nil { - t.Fatal("expected error for plugin exists, got none") - } else if err.Error() != "plugin already exists" { - t.Fatalf("expected error for plugin exists, got (%v)", err) - } + require.EqualErrorf(t, Install(i), "plugin already exists", "expected error for plugin exists") } func TestHTTPInstallerNonExistentVersion(t *testing.T) { @@ -132,20 +112,14 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.2") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with error httpInstaller.getter = &TestHTTPGetter{ @@ -153,9 +127,7 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) { } // attempt to install the plugin - if err := Install(i); err == nil { - t.Fatal("expected error from http client") - } + require.Error(t, Install(i), "expected error from http client") } func TestHTTPInstallerUpdate(t *testing.T) { @@ -164,43 +136,29 @@ func TestHTTPInstallerUpdate(t *testing.T) { source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.1") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with minimal plugin tarball mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) - if err != nil { - t.Fatalf("Could not decode fake tgz plugin: %s", err) - } + require.NoError(t, err, "Could not decode fake tgz plugin") httpInstaller.getter = &TestHTTPGetter{ MockResponse: bytes.NewBuffer(mockTgz), } // install the plugin before updating - if err := Install(i); err != nil { - t.Fatal(err) - } - if i.Path() != helmpath.DataPath("plugins", "fake-plugin") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) - } + require.NoError(t, Install(i)) + require.Equal(t, helmpath.DataPath("plugins", "fake-plugin"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) // Update plugin, should fail because it is not implemented - if err := Update(i); err == nil { - t.Fatal("update method not implemented for http installer") - } + require.Error(t, Update(i), "update method not implemented for http installer") } func TestExtract(t *testing.T) { @@ -229,12 +187,9 @@ func TestExtract(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } // Add pax global headers. This should be ignored. @@ -242,33 +197,24 @@ func TestExtract(t *testing.T) { // Details are in the internal Go function for the tar packaged named // allowedFormats. For a TypeXHeader it will return a message stating // "cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers" - if err := tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: "pax_global_header", Typeflag: tar.TypeXGlobalHeader, - }); err != nil { - t.Fatal(err) - } + })) - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // END tarball creation extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("Did not expect error but got error: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, tempDir), "Did not expect error") // Calculate expected permissions after umask is applied expectedPluginYAMLPerm := os.FileMode(0o600 &^ currentUmask) @@ -276,23 +222,19 @@ func TestExtract(t *testing.T) { pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") if info, err := os.Stat(pluginYAMLFullPath); err != nil { - if errors.Is(err, fs.ErrNotExist) { - t.Fatalf("Expected %s to exist but doesn't", pluginYAMLFullPath) - } + require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", pluginYAMLFullPath) t.Fatal(err) - } else if info.Mode().Perm() != expectedPluginYAMLPerm { - t.Fatalf("Expected %s to have %o mode but has %o (umask: %o)", + } else { + require.Equalf(t, expectedPluginYAMLPerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", pluginYAMLFullPath, expectedPluginYAMLPerm, info.Mode().Perm(), currentUmask) } readmeFullPath := filepath.Join(tempDir, "README.md") if info, err := os.Stat(readmeFullPath); err != nil { - if errors.Is(err, fs.ErrNotExist) { - t.Fatalf("Expected %s to exist but doesn't", readmeFullPath) - } + require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", readmeFullPath) t.Fatal(err) - } else if info.Mode().Perm() != expectedReadmePerm { - t.Fatalf("Expected %s to have %o mode but has %o (umask: %o)", + } else { + require.Equalf(t, expectedReadmePerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", readmeFullPath, expectedReadmePerm, info.Mode().Perm(), currentUmask) } } @@ -313,16 +255,15 @@ func TestCleanJoin(t *testing.T) { {"foo\\bar.txt", "/tmp/foo/bar.txt", false}, {"c:\\foo\\bar.txt", "", true}, } { - out, err := cleanJoin("/tmp", fixture.path) - if err != nil { - if !fixture.expectError { - t.Errorf("Test %d: Path was not cleaned: %s", i, err) + t.Run(strconv.Itoa(i), func(t *testing.T) { + out, err := cleanJoin("/tmp", fixture.path) + if fixture.expectError { + require.Error(t, err, "Test %d: Path was not cleaned", i) + } else { + require.NoError(t, err) + assert.Equal(t, fixture.expect, out, "Test %d: Expected %q but got %q", i, fixture.expect, out) } - continue - } - if fixture.expect != out { - t.Errorf("Test %d: Expected %q but got %q", i, fixture.expect, out) - } + }) } } @@ -336,14 +277,11 @@ func TestMediaTypeToExtension(t *testing.T) { "application/json": false, } { ext, ok := mediaTypeToExtension(mt) - if ok != shouldPass { - t.Errorf("Media type %q failed test", mt) - } - if shouldPass && ext == "" { - t.Error("Expected an extension but got empty string") - } - if !shouldPass && ext != "" { - t.Error("Expected extension to be empty for unrecognized type") + assert.Equal(t, shouldPass, ok, "Media type %q failed test", mt) + if shouldPass { + assert.NotEmpty(t, ext, "Expected an extension but got empty string for media type %q", mt) + } else { + assert.Empty(t, ext, "Expected extension to be empty for unrecognized media type %q", mt) } } } @@ -377,55 +315,41 @@ func TestExtractWithNestedDirectories(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // First extraction - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("First extraction failed: %v", err) - } + require.NoError(t, extractor.Extract(&buf, tempDir), "First extraction failed") // Verify nested structure was created nestedFile := filepath.Join(tempDir, "docs", "examples", "example1.yaml") - if _, err := os.Stat(nestedFile); err != nil { - t.Fatalf("Expected nested file %s to exist but got error: %v", nestedFile, err) - } + _, err = os.Stat(nestedFile) + require.NoErrorf(t, err, "Expected nested file %s to exist", nestedFile) // Reset buffer for second extraction buf.Reset() gz = gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err = gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // Second extraction to same directory (should not fail) - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("Second extraction to existing directory failed: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, tempDir), "Second extraction to existing directory failed") } func TestExtractWithExistingDirectory(t *testing.T) { @@ -434,15 +358,11 @@ func TestExtractWithExistingDirectory(t *testing.T) { // Pre-create the cache directory structure cacheDir := filepath.Join(tempDir, "cache") - if err := os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0o755)) // Create a file in the existing directory existingFile := filepath.Join(cacheDir, "existing", "file.txt") - if err := os.WriteFile(existingFile, []byte("existing content"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(existingFile, []byte("existing content"), 0o644)) // Write a tarball var tarbuf bytes.Buffer @@ -466,47 +386,35 @@ func TestExtractWithExistingDirectory(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Extract to directory with existing content - if err = extractor.Extract(&buf, cacheDir); err != nil { - t.Fatalf("Extraction to directory with existing content failed: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, cacheDir), "Extraction to directory with existing content failed") // Verify new file was created newFile := filepath.Join(cacheDir, "existing", "dir", "newfile.txt") - if _, err := os.Stat(newFile); err != nil { - t.Fatalf("Expected new file %s to exist but got error: %v", newFile, err) - } + _, err = os.Stat(newFile) + require.NoErrorf(t, err, "Expected new file %s to exist but got error", newFile) // Verify existing file is still there - if _, err := os.Stat(existingFile); err != nil { - t.Fatalf("Expected existing file %s to still exist but got error: %v", existingFile, err) - } + _, err = os.Stat(existingFile) + require.NoErrorf(t, err, "Expected existing file %s to still exist", existingFile) } func TestExtractPluginInSubdirectory(t *testing.T) { @@ -536,25 +444,19 @@ func TestExtractPluginInSubdirectory(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // Test the installer @@ -573,24 +475,16 @@ func TestExtractPluginInSubdirectory(t *testing.T) { // Ensure the destination directory doesn't exist // (In a real scenario, this is handled by installer.Install() wrapper) destPath := installer.Path() - if err := os.RemoveAll(destPath); err != nil { - t.Fatalf("Failed to clean destination path: %v", err) - } + require.NoErrorf(t, os.RemoveAll(destPath), "Failed to clean destination path") // Install should handle the subdirectory correctly - if err := installer.Install(); err != nil { - t.Fatalf("Failed to install plugin with subdirectory: %v", err) - } + require.NoErrorf(t, installer.Install(), "Failed to install plugin with subdirectory") // The plugin should be installed from the subdirectory // Check that detectPluginRoot found the correct location pluginRoot, err := detectPluginRoot(tempDir) - if err != nil { - t.Fatalf("Failed to detect plugin root: %v", err) - } + require.NoError(t, err, "Failed to detect plugin root") expectedRoot := filepath.Join(tempDir, "my-plugin") - if pluginRoot != expectedRoot { - t.Errorf("Expected plugin root to be %s but got %s", expectedRoot, pluginRoot) - } + assert.Equal(t, expectedRoot, pluginRoot, "Expected plugin root to be %s but got %s", expectedRoot, pluginRoot) } diff --git a/internal/plugin/installer/local_installer_test.go b/internal/plugin/installer/local_installer_test.go index f46fcb44b..94632756c 100644 --- a/internal/plugin/installer/local_installer_test.go +++ b/internal/plugin/installer/local_installer_test.go @@ -19,11 +19,12 @@ import ( "archive/tar" "bytes" "compress/gzip" - "errors" "os" "path/filepath" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/helmpath" ) @@ -34,40 +35,23 @@ func TestLocalInstaller(t *testing.T) { ensure.HelmHome(t) // Make a temp dir tdir := t.TempDir() - if err := os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0o644)) source := "../testdata/plugdir/good/echo-v1" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) - if err := Install(i); err != nil { - t.Fatal(err) - } + require.NoError(t, Install(i)) - if i.Path() != helmpath.DataPath("plugins", "echo-v1") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) - } + require.Equal(t, helmpath.DataPath("plugins", "echo-v1"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) os.RemoveAll(filepath.Dir(helmpath.DataPath())) // helmpath.DataPath is like /tmp/helm013130971/helm } func TestLocalInstallerNotAFolder(t *testing.T) { source := "../testdata/plugdir/good/echo-v1/plugin.yaml" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - err = Install(i) - if err == nil { - t.Fatal("expected error") - } - if !errors.Is(err, ErrPluginNotADirectory) { - t.Fatalf("expected error to equal: %q", err) - } + require.NoError(t, err) + require.ErrorIs(t, Install(i), ErrPluginNotADirectory) } func TestLocalInstallerTarball(t *testing.T) { @@ -97,53 +81,31 @@ func TestLocalInstallerTarball(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } - if err := tw.Close(); err != nil { - t.Fatal(err) - } - if err := gw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) // Write tarball to file - if err := os.WriteFile(tarballPath, buf.Bytes(), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tarballPath, buf.Bytes(), 0o644)) // Test installation i, err := NewForSource(tarballPath, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // Verify it's detected as LocalInstaller localInstaller, ok := i.(*LocalInstaller) - if !ok { - t.Fatal("expected LocalInstaller") - } - - if !localInstaller.isArchive { - t.Fatal("expected isArchive to be true") - } - - if err := Install(i); err != nil { - t.Fatal(err) - } + require.True(t, ok, "expected LocalInstaller") + require.True(t, localInstaller.isArchive, "expected isArchive to be true") + require.NoError(t, Install(i)) expectedPath := helmpath.DataPath("plugins", "test-plugin") - if i.Path() != expectedPath { - t.Fatalf("expected path %q, got %q", expectedPath, i.Path()) - } + require.Equal(t, expectedPath, i.Path(), "expected path %q, got %q", expectedPath, i.Path()) // Verify plugin was installed - if _, err := os.Stat(i.Path()); err != nil { - t.Fatalf("plugin not found at %s: %v", i.Path(), err) - } + _, err = os.Stat(i.Path()) + require.NoErrorf(t, err, "plugin not found at %s", i.Path()) } From ba31ca0c0b455541f05986e8dcb8a0554fa70dd2 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 087/161] chore(internal): refactor: convert tests to testify assert/require part 1 refactor: convert tests to testify assert/require in internal/plugin/installer Signed-off-by: Matthieu MOREL --- .../plugin/installer/oci_installer_test.go | 316 +++++------------- .../plugin/installer/vcs_installer_test.go | 89 ++--- 2 files changed, 113 insertions(+), 292 deletions(-) diff --git a/internal/plugin/installer/oci_installer_test.go b/internal/plugin/installer/oci_installer_test.go index 48eccf6e1..ce381d12c 100644 --- a/internal/plugin/installer/oci_installer_test.go +++ b/internal/plugin/installer/oci_installer_test.go @@ -64,12 +64,9 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Size: int64(len(pluginYAML)), Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } - if _, err := tarWriter.Write([]byte(pluginYAML)); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) + _, err := tarWriter.Write([]byte(pluginYAML)) + require.NoError(t, err) // Add bin directory dirHeader := &tar.Header{ @@ -77,9 +74,7 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Mode: 0o755, Typeflag: tar.TypeDir, } - if err := tarWriter.WriteHeader(dirHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(dirHeader)) // Add executable execContent := fmt.Sprintf("#!/bin/sh\necho '%s test plugin'", pluginName) @@ -89,12 +84,9 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Size: int64(len(execContent)), Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(execHeader); err != nil { - t.Fatal(err) - } - if _, err := tarWriter.Write([]byte(execContent)); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(execHeader)) + _, err = tarWriter.Write([]byte(execContent)) + require.NoError(t, err) tarWriter.Close() gzWriter.Close() @@ -135,9 +127,7 @@ func mockOCIRegistryWithArtifactType(t *testing.T, pluginName string) (*httptest } manifestData, err := json.Marshal(manifest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) manifestDigest := fmt.Sprintf("sha256:%x", sha256Sum(manifestData)) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -175,9 +165,7 @@ func mockOCIRegistryWithArtifactType(t *testing.T, pluginName string) (*httptest // Parse server URL to get host:port format for OCI reference serverURL, err := url.Parse(server.URL) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) registryHost := serverURL.Host return server, registryHost @@ -240,42 +228,20 @@ func TestNewOCIInstaller(t *testing.T) { installer, err := NewOCIInstaller(tt.source) if tt.expectError { - if err == nil { - t.Error("expected error but got none") - } - return - } - - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - // Check all fields thoroughly - if installer.PluginName != tt.expectName { - t.Errorf("expected plugin name %s, got %s", tt.expectName, installer.PluginName) - } - - if installer.Source != tt.source { - t.Errorf("expected source %s, got %s", tt.source, installer.Source) - } - - if installer.CacheDir == "" { - t.Error("expected non-empty cache directory") - } - - if !strings.Contains(installer.CacheDir, "plugins") { - t.Errorf("expected cache directory to contain 'plugins', got %s", installer.CacheDir) - } - - if installer.settings == nil { - t.Error("expected settings to be initialized") - } - - // Check that Path() method works - expectedPath := helmpath.DataPath("plugins", tt.expectName) - if installer.Path() != expectedPath { - t.Errorf("expected path %s, got %s", expectedPath, installer.Path()) + require.Error(t, err) + } else { + require.NoError(t, err) + + // Check all fields thoroughly + assert.Equal(t, tt.expectName, installer.PluginName, "expected plugin name %s, got %s", tt.expectName, installer.PluginName) + assert.Equal(t, tt.source, installer.Source, "expected source %s, got %s", tt.source, installer.Source) + assert.NotEmpty(t, installer.CacheDir, "expected non-empty cache directory") + assert.Contains(t, installer.CacheDir, "plugins", "expected cache directory to contain 'plugins', got %s", installer.CacheDir) + assert.NotNil(t, installer.settings, "expected settings to be initialized") + + // Check that Path() method works + expectedPath := helmpath.DataPath("plugins", tt.expectName) + assert.Equal(t, expectedPath, installer.Path(), "expected path %s, got %s", expectedPath, installer.Path()) } }) } @@ -311,9 +277,7 @@ func TestOCIInstaller_Path(t *testing.T) { } path := installer.Path() - if path != tt.expectPath { - t.Errorf("expected path %s, got %s", tt.expectPath, path) - } + assert.Equal(t, tt.expectPath, path, "expected path %s, got %s", tt.expectPath, path) }) } } @@ -331,39 +295,30 @@ func TestOCIInstaller_Install(t *testing.T) { // Test with plain HTTP (since test server uses HTTP) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // The OCI installer uses helmpath.DataPath, which is isolated by ensure.HelmHome(t) actualPath := installer.Path() t.Logf("Installer will use path: %s", actualPath) // Install the plugin - if err := Install(installer); err != nil { - t.Fatalf("Expected installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected installation to succeed") // Verify plugin was installed to the correct location - if !isPlugin(actualPath) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", actualPath) - } + assert.Truef(t, isPlugin(actualPath), "Expected plugin directory %s to contain plugin.yaml", actualPath) // Debug: list what was actually created - if entries, err := os.ReadDir(actualPath); err != nil { - t.Fatalf("Could not read plugin directory %s: %v", actualPath, err) - } else { - t.Logf("Plugin directory %s contains:", actualPath) - for _, entry := range entries { - t.Logf(" - %s", entry.Name()) - } + entries, err := os.ReadDir(actualPath) + require.NoError(t, err, "Could not read plugin directory %s", actualPath) + t.Logf("Plugin directory %s contains:", actualPath) + for _, entry := range entries { + t.Logf(" - %s", entry.Name()) } // Verify the plugin.yaml file exists and is valid pluginFile := filepath.Join(actualPath, "plugin.yaml") - if _, err := os.Stat(pluginFile); err != nil { - t.Errorf("Expected plugin.yaml to exist, got error: %v", err) - } + _, err = os.Stat(pluginFile) + assert.NoErrorf(t, err, "Expected plugin.yaml to exist") } func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { @@ -404,11 +359,9 @@ func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, tc.pluginName) installer, err := NewOCIInstaller(source, tc.options...) - if err != nil { - if !tc.wantErr { - t.Fatalf("Expected no error creating installer, got %v", err) - } - return + + if !tc.wantErr { + require.NoError(t, err, "Expected no error creating installer") } // The installer now uses our isolated test directory @@ -419,7 +372,7 @@ func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { if tc.wantErr { require.Error(t, err, "Expected installation to fail, but it succeeded") } else { - require.NoError(t, err, "Expected installation to succeed, got error: %v", err) + require.NoError(t, err, "Expected installation to succeed") // Verify plugin was installed to the actual path assert.True(t, isPlugin(actualPath), "Expected plugin directory %s to contain plugin.yaml", actualPath) } @@ -437,27 +390,16 @@ func TestOCIInstaller_Install_AlreadyExists(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, pluginName) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // First install should succeed - if err := Install(installer); err != nil { - t.Fatalf("Expected first installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected first installation to succeed") // Verify plugin was installed - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml", installer.Path()) // Second install should fail with "plugin already exists" - err = Install(installer) - if err == nil { - t.Error("Expected error when installing plugin that already exists") - } else if !strings.Contains(err.Error(), "plugin already exists") { - t.Errorf("Expected 'plugin already exists' error, got: %v", err) - } + assert.ErrorContains(t, Install(installer), "plugin already exists") } func TestOCIInstaller_Update(t *testing.T) { @@ -470,38 +412,23 @@ func TestOCIInstaller_Update(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, pluginName) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // Test update when plugin does not exist - should fail - err = Update(installer) - if err == nil { - t.Error("Expected error when updating plugin that does not exist") - } else if !strings.Contains(err.Error(), "plugin does not exist") { - t.Errorf("Expected 'plugin does not exist' error, got: %v", err) - } + require.ErrorContains(t, Update(installer), "plugin does not exist") // Install plugin first - if err := Install(installer); err != nil { - t.Fatalf("Expected installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected installation to succeed") // Verify plugin was installed - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml", installer.Path()) // Test update when plugin exists - should succeed // For OCI, Update() removes old version and reinstalls - if err := Update(installer); err != nil { - t.Errorf("Expected update to succeed, got error: %v", err) - } + require.NoErrorf(t, Update(installer), "Expected update to succeed") // Verify plugin is still installed after update - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml after update", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml after update", installer.Path()) } func TestOCIInstaller_Install_ComponentExtraction(t *testing.T) { @@ -513,35 +440,26 @@ func TestOCIInstaller_Install_ComponentExtraction(t *testing.T) { pluginData := createTestPluginTarGz(t, pluginName) // Test extraction - err := extractTarGz(bytes.NewReader(pluginData), tempDir) - if err != nil { - t.Fatalf("Failed to extract plugin: %v", err) - } + require.NoError(t, extractTarGz(bytes.NewReader(pluginData), tempDir), "Failed to extract plugin") // Verify plugin.yaml exists pluginYAMLPath := filepath.Join(tempDir, "plugin.yaml") - if _, err := os.Stat(pluginYAMLPath); os.IsNotExist(err) { - t.Error("plugin.yaml not found after extraction") - } + _, err := os.Stat(pluginYAMLPath) + assert.False(t, os.IsNotExist(err), "plugin.yaml not found after extraction") // Verify bin directory exists binPath := filepath.Join(tempDir, "bin") - if _, err := os.Stat(binPath); os.IsNotExist(err) { - t.Error("bin directory not found after extraction") - } + _, err = os.Stat(binPath) + assert.False(t, os.IsNotExist(err), "bin directory not found after extraction") // Verify executable exists and has correct permissions execPath := filepath.Join(tempDir, "bin", pluginName) - if info, err := os.Stat(execPath); err != nil { - t.Errorf("executable not found: %v", err) - } else if info.Mode()&0o111 == 0 { - t.Error("file is not executable") - } + info, err := os.Stat(execPath) + require.NoError(t, err, "executable not found") + assert.NotEqual(t, 0, info.Mode()&0o111, "file is not executable") // Verify this would be recognized as a plugin - if !isPlugin(tempDir) { - t.Error("extracted directory is not a valid plugin") - } + assert.True(t, isPlugin(tempDir), "extracted directory is not a valid plugin") } func TestExtractTarGz(t *testing.T) { @@ -561,13 +479,10 @@ func TestExtractTarGz(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) // Add a test directory dirHeader := &tar.Header{ @@ -576,35 +491,25 @@ func TestExtractTarGz(t *testing.T) { Typeflag: tar.TypeDir, } - if err := tarWriter.WriteHeader(dirHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(dirHeader)) tarWriter.Close() gzWriter.Close() // Test extraction - err := extractTarGz(bytes.NewReader(buf.Bytes()), tempDir) - if err != nil { - t.Errorf("extractTarGz failed: %v", err) - } + require.NoError(t, extractTarGz(bytes.NewReader(buf.Bytes()), tempDir), "extractTarGz failed") // Verify extracted file extractedFile := filepath.Join(tempDir, "test-file.txt") content, err := os.ReadFile(extractedFile) - if err != nil { - t.Errorf("failed to read extracted file: %v", err) - } + require.NoError(t, err, "failed to read extracted file") - if string(content) != testContent { - t.Errorf("expected content %s, got %s", testContent, string(content)) - } + assert.Equal(t, testContent, string(content), "expected content %s, got %s", testContent, string(content)) // Verify extracted directory extractedDir := filepath.Join(tempDir, "test-dir") - if _, err := os.Stat(extractedDir); os.IsNotExist(err) { - t.Errorf("extracted directory does not exist: %s", extractedDir) - } + _, err = os.Stat(extractedDir) + assert.Falsef(t, os.IsNotExist(err), "extracted directory does not exist: %s", extractedDir) } func TestExtractTarGz_InvalidGzip(t *testing.T) { @@ -612,10 +517,7 @@ func TestExtractTarGz_InvalidGzip(t *testing.T) { // Test with invalid gzip data invalidGzipData := []byte("not gzip data") - err := extractTarGz(bytes.NewReader(invalidGzipData), tempDir) - if err == nil { - t.Error("expected error for invalid gzip data") - } + assert.Error(t, extractTarGz(bytes.NewReader(invalidGzipData), tempDir), "expected error for invalid gzip data") } func TestExtractTar_UnknownFileType(t *testing.T) { @@ -634,13 +536,10 @@ func TestExtractTar_UnknownFileType(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) // Test unknown file type unknownHeader := &tar.Header{ @@ -649,21 +548,12 @@ func TestExtractTar_UnknownFileType(t *testing.T) { Typeflag: tar.TypeSymlink, // Use a type that's not handled } - if err := tarWriter.WriteHeader(unknownHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(unknownHeader)) tarWriter.Close() // Test extraction - should fail due to unknown type - err := extractTar(bytes.NewReader(buf.Bytes()), tempDir) - if err == nil { - t.Error("expected error for unknown tar file type") - } - - if !strings.Contains(err.Error(), "unknown type") { - t.Errorf("expected 'unknown type' error, got: %v", err) - } + assert.ErrorContains(t, extractTar(bytes.NewReader(buf.Bytes()), tempDir), "unknown type") } func TestExtractTar_SuccessfulExtraction(t *testing.T) { @@ -686,32 +576,22 @@ func TestExtractTar_SuccessfulExtraction(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) tarWriter.Close() // Test extraction - err := extractTar(bytes.NewReader(buf.Bytes()), tempDir) - if err != nil { - t.Errorf("extractTar failed: %v", err) - } + require.NoError(t, extractTar(bytes.NewReader(buf.Bytes()), tempDir), "extractTar failed") // Verify the regular file was extracted extractedFile := filepath.Join(tempDir, "test-file.txt") content, err := os.ReadFile(extractedFile) - if err != nil { - t.Errorf("failed to read extracted file: %v", err) - } + require.NoError(t, err, "failed to read extracted file") - if string(content) != testContent { - t.Errorf("expected content %s, got %s", testContent, string(content)) - } + assert.Equal(t, testContent, string(content), "expected content %s, got %s", testContent, string(content)) } func TestOCIInstaller_Install_PlainHTTPOption(t *testing.T) { @@ -720,41 +600,25 @@ func TestOCIInstaller_Install_PlainHTTPOption(t *testing.T) { // Test with PlainHTTP=false (default) installer1, err := NewOCIInstaller(source) - if err != nil { - t.Fatalf("failed to create installer: %v", err) - } - if installer1.getter == nil { - t.Error("getter should be initialized") - } + require.NoError(t, err, "failed to create installer") + assert.NotNil(t, installer1.getter, "getter should be initialized") // Test with PlainHTTP=true installer2, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("failed to create installer with PlainHTTP=true: %v", err) - } - if installer2.getter == nil { - t.Error("getter should be initialized with PlainHTTP=true") - } + require.NoError(t, err, "failed to create installer with PlainHTTP=true") + assert.NotNil(t, installer2.getter, "getter should be initialized with PlainHTTP=true") // Both installers should have the same basic properties - if installer1.PluginName != installer2.PluginName { - t.Error("plugin names should match") - } - if installer1.Source != installer2.Source { - t.Error("sources should match") - } + assert.Equal(t, installer2.PluginName, installer1.PluginName, "plugin names should match") + assert.Equal(t, installer2.Source, installer1.Source, "sources should match") // Test with multiple options installer3, err := NewOCIInstaller(source, getter.WithPlainHTTP(true), getter.WithBasicAuth("user", "pass"), ) - if err != nil { - t.Fatalf("failed to create installer with multiple options: %v", err) - } - if installer3.getter == nil { - t.Error("getter should be initialized with multiple options") - } + require.NoError(t, err, "failed to create installer with multiple options") + assert.NotNil(t, installer3.getter, "getter should be initialized with multiple options") } func TestOCIInstaller_Install_ValidationErrors(t *testing.T) { @@ -789,12 +653,8 @@ func TestOCIInstaller_Install_ValidationErrors(t *testing.T) { // Test the gzip validation logic that's used in the Install method if len(tt.layerData) < 2 || tt.layerData[0] != 0x1f || tt.layerData[1] != 0x8b { // This matches the validation in the Install method - if !tt.expectError { - t.Error("expected valid gzip data") - } - if !strings.Contains(tt.errorMsg, "is not a gzip compressed archive") { - t.Error("expected error message to contain 'is not a gzip compressed archive'") - } + assert.True(t, tt.expectError, "expected valid gzip data") + assert.Contains(t, tt.errorMsg, "is not a gzip compressed archive") } }) } diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 7e44cc957..3f5b098e4 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/Masterminds/vcs" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/helmpath" @@ -52,9 +53,7 @@ func (r *testRepo) UpdateVersion(version string) error { func TestVCSInstaller(t *testing.T) { ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) source := "https://github.com/adamreese/helm-env" testRepoPath, _ := filepath.Abs("../testdata/plugdir/good/echo-v1") @@ -64,43 +63,27 @@ func TestVCSInstaller(t *testing.T) { } i, err := NewForSource(source, "~0.1.0") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned vcsInstaller, ok := i.(*VCSInstaller) - if !ok { - t.Fatal("expected a VCSInstaller") - } + require.True(t, ok, "expected a VCSInstaller") // set the testRepo in the VCSInstaller vcsInstaller.Repo = repo - if err := Install(i); err != nil { - t.Fatal(err) - } - if repo.current != "0.1.1" { - t.Fatalf("expected version '0.1.1', got %q", repo.current) - } + require.NoError(t, Install(i)) + require.Equal(t, "0.1.1", repo.current, "expected version '0.1.1', got %q", repo.current) expectedPath := helmpath.DataPath("plugins", "helm-env") - if i.Path() != expectedPath { - t.Fatalf("expected path %q, got %q", expectedPath, i.Path()) - } + require.Equal(t, expectedPath, i.Path(), "expected path %q, got %q", expectedPath, i.Path()) // Install again to test plugin exists error - if err := Install(i); err == nil { - t.Fatal("expected error for plugin exists, got none") - } else if err.Error() != "plugin already exists" { - t.Fatalf("expected error for plugin exists, got (%v)", err) - } + require.EqualErrorf(t, Install(i), "plugin already exists", "expected error for plugin exists") // Testing FindSource method, expect error because plugin code is not a cloned repository - if _, err := FindSource(i.Path()); err == nil { - t.Fatal("expected error for inability to find plugin source, got none") - } else if err.Error() != "cannot get information about plugin source" { - t.Fatalf("expected error for inability to find plugin source, got (%v)", err) - } + _, err = FindSource(i.Path()) + require.Error(t, err, "expected error for inability to find plugin source, got none") + require.EqualErrorf(t, err, "cannot get information about plugin source", "expected error for inability to find plugin source") } func TestVCSInstallerNonExistentVersion(t *testing.T) { @@ -110,21 +93,18 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { version := "0.2.0" i, err := NewForSource(source, version) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned - if _, ok := i.(*VCSInstaller); !ok { - t.Fatal("expected a VCSInstaller") - } + _, ok := i.(*VCSInstaller) + require.True(t, ok, "expected a VCSInstaller") if err := Install(i); err == nil { t.Fatal("expected error for version does not exists, got none") } else if strings.Contains(err.Error(), "Could not resolve host: github.com") { t.Skip("Unable to run test without Internet access") - } else if err.Error() != fmt.Sprintf("requested version %q does not exist for plugin %q", version, source) { - t.Fatalf("expected error for version does not exists, got (%v)", err) + } else { + require.EqualErrorf(t, err, fmt.Sprintf("requested version %q does not exist for plugin %q", version, source), "expected error for version does not exists") } } func TestVCSInstallerUpdate(t *testing.T) { @@ -133,20 +113,13 @@ func TestVCSInstallerUpdate(t *testing.T) { source := "https://github.com/adamreese/helm-env" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned - if _, ok := i.(*VCSInstaller); !ok { - t.Fatal("expected a VCSInstaller") - } + _, ok := i.(*VCSInstaller) + require.True(t, ok, "expected a VCSInstaller") - if err := Update(i); err == nil { - t.Fatal("expected error for plugin does not exist, got none") - } else if err.Error() != "plugin does not exist" { - t.Fatalf("expected error for plugin does not exist, got (%v)", err) - } + require.EqualErrorf(t, Update(i), "plugin does not exist", "expected error for plugin does not exist") // Install plugin before update if err := Install(i); err != nil { @@ -159,30 +132,18 @@ func TestVCSInstallerUpdate(t *testing.T) { // Test FindSource method for positive result pluginInfo, err := FindSource(i.Path()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vcsInstaller := pluginInfo.(*VCSInstaller) repoRemote := vcsInstaller.Repo.Remote() - if repoRemote != source { - t.Fatalf("invalid source found, expected %q got %q", source, repoRemote) - } + require.Equal(t, source, repoRemote, "invalid source found, expected %q got %q", source, repoRemote) // Update plugin - if err := Update(i); err != nil { - t.Fatal(err) - } + require.NoError(t, Update(i)) // Test update failure - if err := os.Remove(filepath.Join(vcsInstaller.Repo.LocalPath(), "plugin.yaml")); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(filepath.Join(vcsInstaller.Repo.LocalPath(), "plugin.yaml"))) // Testing update for error - if err := Update(vcsInstaller); err == nil { - t.Fatal("expected error for plugin modified, got none") - } else if err.Error() != "plugin repo was modified" { - t.Fatalf("expected error for plugin modified, got (%v)", err) - } + require.EqualErrorf(t, Update(vcsInstaller), "plugin repo was modified", "expected error for plugin modified") } From f3402c1cd69b84d278af5a30551e376d727d27c1 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 088/161] chore(internal): refactor: convert tests to testify assert/require part 6 refactor: convert tests to testify assert/require in internal/plugin Signed-off-by: Matthieu MOREL --- .../chart/v3/lint/rules/deprecations_test.go | 2 +- internal/chart/v3/lint/rules/values_test.go | 5 ++-- internal/chart/v3/util/validate_name_test.go | 28 ++++++++++--------- internal/fileutil/fileutil_test.go | 12 +++----- internal/logging/logging_test.go | 6 ++-- internal/plugin/installer/base_test.go | 6 ++-- internal/plugin/loader_test.go | 8 ++---- internal/plugin/metadata_test.go | 10 +++---- internal/plugin/metadata_v1_test.go | 3 +- internal/plugin/plugin_test.go | 10 +++---- internal/release/v2/hook_test.go | 23 +++++++-------- internal/sympath/walk_test.go | 3 +- 12 files changed, 49 insertions(+), 67 deletions(-) diff --git a/internal/chart/v3/lint/rules/deprecations_test.go b/internal/chart/v3/lint/rules/deprecations_test.go index 920fdc31f..96462bc15 100644 --- a/internal/chart/v3/lint/rules/deprecations_test.go +++ b/internal/chart/v3/lint/rules/deprecations_test.go @@ -32,7 +32,7 @@ func TestValidateNoDeprecations(t *testing.T) { require.Error(t, err, "Expected deprecated extension to be flagged") var depErr deprecatedAPIError require.ErrorAs(t, err, &depErr, "Expected error to be of type deprecatedAPIError") - require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank: %v", err) + require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank") assert.NoError(t, validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index c87607f2d..7f1177729 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -56,8 +56,7 @@ func TestValidateValuesYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm) defer os.Remove(nonExistingValuesFilePath) - err := validateValuesFileExistence(nonExistingValuesFilePath) - assert.Error(t, err, "validateValuesFileExistence to return a linter error, got no error") + assert.Error(t, validateValuesFileExistence(nonExistingValuesFilePath), "validateValuesFileExistence to return a linter error, got no error") } func TestValidateValuesFileWellFormed(t *testing.T) { @@ -150,7 +149,7 @@ func TestValidateValuesFile(t *testing.T) { require.NoError(t, err, "Failed validation") } else { require.Error(t, err, "expected values file to fail parsing") - assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") + assert.ErrorContains(t, err, tt.errorMessage) } }) } diff --git a/internal/chart/v3/util/validate_name_test.go b/internal/chart/v3/util/validate_name_test.go index cfc62a0f7..3ea768db2 100644 --- a/internal/chart/v3/util/validate_name_test.go +++ b/internal/chart/v3/util/validate_name_test.go @@ -16,7 +16,11 @@ limitations under the License. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) // TestValidateReleaseName is a regression test for ValidateName // @@ -46,12 +50,11 @@ func TestValidateReleaseName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateReleaseName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateReleaseName(input) + if expectPass { + assert.NoErrorf(t, err, "Expected release name %q to pass validation", input) + } else { + assert.Errorf(t, err, "Expected release name %q to fail validation, but it passed", input) } } } @@ -80,12 +83,11 @@ func TestValidateMetadataName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateMetadataName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateMetadataName(input) + if expectPass { + assert.NoError(t, err, "Expected %q to succeed", input) + } else { + assert.Error(t, err, "Expected %q to fail", input) } } } diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go index 9c997fcd3..85dd51894 100644 --- a/internal/fileutil/fileutil_test.go +++ b/internal/fileutil/fileutil_test.go @@ -37,8 +37,7 @@ func TestAtomicWriteFile(t *testing.T) { reader := bytes.NewReader([]byte(stringContent)) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err) + require.NoError(t, AtomicWriteFile(testpath, reader, mode)) got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -58,8 +57,7 @@ func TestAtomicWriteFile_CreateTempError(t *testing.T) { reader := bytes.NewReader([]byte("test content")) mode := os.FileMode(0o644) - err := AtomicWriteFile(invalidPath, reader, mode) - assert.Error(t, err, "Expected error when CreateTemp fails") + assert.Error(t, AtomicWriteFile(invalidPath, reader, mode), "Expected error when CreateTemp fails") } // TestAtomicWriteFile_EmptyContent tests with empty content @@ -70,8 +68,7 @@ func TestAtomicWriteFile_EmptyContent(t *testing.T) { reader := bytes.NewReader([]byte("")) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err, "AtomicWriteFile error with empty content") + require.NoError(t, AtomicWriteFile(testpath, reader, mode), "AtomicWriteFile error with empty content") got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -89,8 +86,7 @@ func TestAtomicWriteFile_LargeContent(t *testing.T) { reader := bytes.NewReader([]byte(largeContent)) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err, "AtomicWriteFile error with large content") + require.NoError(t, AtomicWriteFile(testpath, reader, mode), "AtomicWriteFile error with large content") got, err := os.ReadFile(testpath) require.NoError(t, err) diff --git a/internal/logging/logging_test.go b/internal/logging/logging_test.go index 83979e9db..1d6eaf852 100644 --- a/internal/logging/logging_test.go +++ b/internal/logging/logging_test.go @@ -197,9 +197,8 @@ func TestDebugCheckHandler_Handle(t *testing.T) { } record := slog.NewRecord(time.Now(), slog.LevelInfo, "test message", 0) - err := handler.Handle(t.Context(), record) - require.NoError(t, err) + require.NoError(t, handler.Handle(t.Context(), record)) assert.Contains(t, buf.String(), "test message") }) @@ -214,9 +213,8 @@ func TestDebugCheckHandler_Handle(t *testing.T) { type testKey string ctx := context.WithValue(t.Context(), testKey("test"), "value") record := slog.NewRecord(time.Now(), slog.LevelInfo, "context test", 0) - err := handler.Handle(ctx, record) - require.NoError(t, err) + require.NoError(t, handler.Handle(ctx, record)) assert.Contains(t, buf.String(), "context test") }) } diff --git a/internal/plugin/installer/base_test.go b/internal/plugin/installer/base_test.go index b7902e699..8ef7ff588 100644 --- a/internal/plugin/installer/base_test.go +++ b/internal/plugin/installer/base_test.go @@ -15,6 +15,8 @@ package installer import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestPath(t *testing.T) { @@ -38,8 +40,6 @@ func TestPath(t *testing.T) { t.Setenv("HELM_PLUGINS", tt.helmPluginsDir) baseIns := newBase(tt.source) baseInsPath := baseIns.Path() - if baseInsPath != tt.expectPath { - t.Errorf("expected name %s, got %s", tt.expectPath, baseInsPath) - } + assert.Equal(t, tt.expectPath, baseInsPath, "expected name %s, got %s", tt.expectPath, baseInsPath) } } diff --git a/internal/plugin/loader_test.go b/internal/plugin/loader_test.go index 4b98a6f83..e0682aed7 100644 --- a/internal/plugin/loader_test.go +++ b/internal/plugin/loader_test.go @@ -194,13 +194,9 @@ func TestDetectDuplicates(t *testing.T) { mockSubprocessCLIPlugin(t, "foo"), mockSubprocessCLIPlugin(t, "bar"), } - if err := detectDuplicates(plugs); err != nil { - t.Error("no duplicates in the first set") - } + require.NoError(t, detectDuplicates(plugs), "no duplicates in the first set") plugs = append(plugs, mockSubprocessCLIPlugin(t, "foo")) - if err := detectDuplicates(plugs); err == nil { - t.Error("duplicates in the second set") - } + assert.Error(t, detectDuplicates(plugs), "duplicates in the second set") } func TestLoadAllDir_Empty(t *testing.T) { diff --git a/internal/plugin/metadata_test.go b/internal/plugin/metadata_test.go index b4994cf68..9cfdbc83a 100644 --- a/internal/plugin/metadata_test.go +++ b/internal/plugin/metadata_test.go @@ -66,7 +66,7 @@ func TestValidatePluginData(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) { err := item.plug.Metadata().Validate() if item.pass { - require.NoError(t, err, "failed to validate case %d: %s", i, err) + require.NoError(t, err, "failed to validate case %d", i) } else { require.Error(t, err, "expected case %d to fail", i) assert.ErrorContains(t, err, item.errString, "expected case %d error to contain %q", i, item.errString) @@ -97,8 +97,7 @@ func TestMetadataValidateVersion(t *testing.T) { t.Run(name, func(t *testing.T) { m := mockSubprocessCLIPlugin(t, "testplugin") m.metadata.Version = tc.version - err := m.Metadata().Validate() - assert.NoError(t, err) + assert.NoError(t, m.Metadata().Validate()) }) } @@ -106,8 +105,7 @@ func TestMetadataValidateVersion(t *testing.T) { t.Run(name, func(t *testing.T) { m := mockSubprocessCLIPlugin(t, "testplugin") m.metadata.Version = tc.version - err := m.Metadata().Validate() - assert.ErrorContains(t, err, "invalid plugin version") + assert.ErrorContains(t, m.Metadata().Validate(), "invalid plugin version") }) } } @@ -139,7 +137,7 @@ func TestMetadataValidateMultipleErrors(t *testing.T) { } for _, expectedErr := range expectedErrors { - assert.Contains(t, errStr, expectedErr, "expected error to contain %q, but got: %v", expectedErr, errStr) + require.ErrorContains(t, err, expectedErr) } // Verify that the error contains the correct number of error messages diff --git a/internal/plugin/metadata_v1_test.go b/internal/plugin/metadata_v1_test.go index 74c67178e..8a6f28705 100644 --- a/internal/plugin/metadata_v1_test.go +++ b/internal/plugin/metadata_v1_test.go @@ -77,8 +77,7 @@ func TestMetadataV1ValidateVersion(t *testing.T) { t.Run("invalid/"+name, func(t *testing.T) { m := base() m.Version = tc.version - err := m.Validate() - assert.ErrorContains(t, err, tc.errMsg) + assert.ErrorContains(t, m.Validate(), tc.errMsg) }) } } diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go index 2e3f274f2..947792046 100644 --- a/internal/plugin/plugin_test.go +++ b/internal/plugin/plugin_test.go @@ -18,6 +18,8 @@ package plugin import ( "testing" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/internal/plugin/schema" ) @@ -34,9 +36,7 @@ func TestValidPluginName(t *testing.T) { for name, pluginName := range validNames { t.Run("valid/"+name, func(t *testing.T) { - if !validPluginName.MatchString(pluginName) { - t.Errorf("expected %q to match validPluginName regex", pluginName) - } + assert.Truef(t, validPluginName.MatchString(pluginName), "expected %q to match validPluginName regex", pluginName) }) } @@ -52,9 +52,7 @@ func TestValidPluginName(t *testing.T) { for name, pluginName := range invalidNames { t.Run("invalid/"+name, func(t *testing.T) { - if validPluginName.MatchString(pluginName) { - t.Errorf("expected %q to not match validPluginName regex", pluginName) - } + assert.Falsef(t, validPluginName.MatchString(pluginName), "expected %q to not match validPluginName regex", pluginName) }) } } diff --git a/internal/release/v2/hook_test.go b/internal/release/v2/hook_test.go index 5a0867398..3e946825e 100644 --- a/internal/release/v2/hook_test.go +++ b/internal/release/v2/hook_test.go @@ -170,12 +170,12 @@ func TestHookExecutionUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &exec) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) + assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) + assert.Equal(t, tt.expected.Phase, exec.Phase) } - require.NoError(t, err) - assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) - assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) - assert.Equal(t, tt.expected.Phase, exec.Phase) }) } } @@ -194,8 +194,7 @@ func TestHookExecutionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded HookExecution - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.StartedAt.Unix(), decoded.StartedAt.Unix()) assert.Equal(t, original.CompletedAt.Unix(), decoded.CompletedAt.Unix()) @@ -208,12 +207,11 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { input := `{"started_at":"","completed_at":"","phase":"Succeeded"}` var exec HookExecution - err := json.Unmarshal([]byte(input), &exec) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &exec)) // Verify time fields are zero values - assert.True(t, exec.StartedAt.IsZero()) - assert.True(t, exec.CompletedAt.IsZero()) + assert.Zero(t, exec.StartedAt) + assert.Zero(t, exec.CompletedAt) assert.Equal(t, HookPhaseSucceeded, exec.Phase) // Marshal back and verify empty time fields are omitted @@ -221,8 +219,7 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted assert.NotContains(t, result, "started_at") diff --git a/internal/sympath/walk_test.go b/internal/sympath/walk_test.go index 76ed39cac..5dd051e4d 100644 --- a/internal/sympath/walk_test.go +++ b/internal/sympath/walk_test.go @@ -132,8 +132,7 @@ func TestWalk(t *testing.T) { return mark(info, err, &errors, true) } // Expect no errors. - err := Walk(tree.name, markFn) - require.NoError(t, err) + require.NoError(t, Walk(tree.name, markFn)) require.Empty(t, errors, "unexpected errors") checkMarks(t, true) From f1d5979e7d8b9d1e36b3cf703d150e8078c2e16e Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 089/161] chore(internal): refactor: convert tests to testify assert/require part 5 refactor: convert tests to testify assert/require in internal/plugin/installer Signed-off-by: Matthieu MOREL --- internal/chart/v3/lint/rules/template_test.go | 27 ++- .../chart/v3/lint/support/message_test.go | 29 +-- internal/chart/v3/util/chartfile_test.go | 27 +-- internal/plugin/installer/installer_test.go | 26 +-- .../plugin/installer/plugin_structure_test.go | 31 +-- .../plugin/installer/verification_test.go | 181 +++++------------- internal/plugin/runtime_extismv1_test.go | 3 +- internal/plugin/subprocess_commands_test.go | 28 +-- internal/plugin/verify_test.go | 26 +-- 9 files changed, 118 insertions(+), 260 deletions(-) diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index 0b83e1cd5..b4fa2d311 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -37,13 +37,11 @@ const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { - err := validateAllowedExtension(test) - require.ErrorContains(t, err, "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) + require.ErrorContains(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { - err := validateAllowedExtension(test) - assert.NoError(t, err, "validateAllowedExtension('%s') to return no error", test) + assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } } @@ -58,8 +56,7 @@ func TestTemplateParsing(t *testing.T) { res := linter.Messages require.Len(t, res, 1, "Expected one error, got %d, %v", len(res), res) - - assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError", "Unexpected error: %s", res[0]) + assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") @@ -86,7 +83,7 @@ func TestMultiTemplateFail(t *testing.T) { require.Len(t, res, 1, "Expected 1 error, got %d, %v", len(res), res) - assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements", "Unexpected error: %s", res[0].Err) + assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements") } func TestValidateMetadataName(t *testing.T) { @@ -292,8 +289,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err := validateMatchSelector(md, manifest) - require.NoError(t, err) + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -315,8 +311,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err = validateMatchSelector(md, manifest) - require.NoError(t, err) + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -335,8 +330,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err = validateMatchSelector(md, manifest) - assert.Error(t, err, "expected Deployment with no selector to fail") + assert.Error(t, validateMatchSelector(md, manifest), "expected Deployment with no selector to fail") } func TestValidateTopIndentLevel(t *testing.T) { @@ -349,8 +343,11 @@ func TestValidateTopIndentLevel(t *testing.T) { " apiVersion:foo": true, "\n\n apiVersion:foo\n\n": true, } { - if err := validateTopIndentLevel(doc); (err == nil) == shouldFail { - t.Errorf("Expected %t for %q", shouldFail, doc) + err := validateTopIndentLevel(doc) + if shouldFail { + assert.Errorf(t, err, "Expected %t for %q", shouldFail, doc) + } else { + assert.NoErrorf(t, err, "Expected %t for %q", shouldFail, doc) } } } diff --git a/internal/chart/v3/lint/support/message_test.go b/internal/chart/v3/lint/support/message_test.go index ce5b5e42e..4c3ed3a3f 100644 --- a/internal/chart/v3/lint/support/message_test.go +++ b/internal/chart/v3/lint/support/message_test.go @@ -19,6 +19,9 @@ package support import ( "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var errLint = errors.New("lint failed") @@ -47,33 +50,19 @@ func TestRunLinterRule(t *testing.T) { linter := Linter{} for _, test := range tests { isValid := linter.RunLinterRule(test.Severity, "chart", test.LintError) - if len(linter.Messages) != test.ExpectedMessages { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) - } - - if linter.HighestSeverity != test.ExpectedHighestSeverity { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) - } - - if isValid != test.ExpectedReturn { - t.Errorf("RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) - } + assert.Lenf(t, linter.Messages, test.ExpectedMessages, "RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) + assert.Equalf(t, test.ExpectedHighestSeverity, linter.HighestSeverity, "RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) + assert.Equalf(t, test.ExpectedReturn, isValid, "RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) } } func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - if m.Error() != "[ERROR] Chart.yaml: Foo" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualErrorf(t, m, "[ERROR] Chart.yaml: Foo", "Unexpected output: %s", m.Error()) m = Message{WarningSev, "templates/", errors.New("Bar")} - if m.Error() != "[WARNING] templates/: Bar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualErrorf(t, m, "[WARNING] templates/: Bar", "Unexpected output: %s", m.Error()) m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - if m.Error() != "[INFO] templates/rc.yaml: FooBar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + assert.EqualErrorf(t, m, "[INFO] templates/rc.yaml: FooBar", "Unexpected output: %s", m.Error()) } diff --git a/internal/chart/v3/util/chartfile_test.go b/internal/chart/v3/util/chartfile_test.go index c791930c1..0cc8a66af 100644 --- a/internal/chart/v3/util/chartfile_test.go +++ b/internal/chart/v3/util/chartfile_test.go @@ -29,10 +29,7 @@ const testfile = "testdata/chartfiletest.yaml" func TestLoadChartfile(t *testing.T) { f, err := LoadChartfile(testfile) - if err != nil { - t.Errorf("Failed to open %s: %s", testfile, err) - return - } + require.NoErrorf(t, err, "Failed to open %s", testfile) verifyChartfile(t, f, "frobnitz") } @@ -64,13 +61,11 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { require.Len(t, f.Annotations, 2, "Unexpected annotations") - if want, got := "extravalue", f.Annotations["extrakey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } + want, got := "extravalue", f.Annotations["extrakey"] + assert.Equalf(t, want, got, "Want %q, but got %q", want, got) - if want, got := "anothervalue", f.Annotations["anotherkey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } + want, got = "anothervalue", f.Annotations["anotherkey"] + assert.Equalf(t, want, got, "Want %q, but got %q", want, got) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { @@ -80,13 +75,9 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { func TestIsChartDir(t *testing.T) { validChartDir, err := IsChartDir("testdata/frobnitz") - if !validChartDir { - t.Errorf("unexpected error while reading chart-directory: (%v)", err) - return - } + require.NoError(t, err, "while reading chart-directory") + require.True(t, validChartDir, "expected valid chart directory") validChartDir, err = IsChartDir("testdata") - if validChartDir || err == nil { - t.Error("expected error but did not get any") - return - } + require.Error(t, err) + require.False(t, validChartDir, "expected invalid chart directory") } diff --git a/internal/plugin/installer/installer_test.go b/internal/plugin/installer/installer_test.go index 50e8e1ee2..620afc183 100644 --- a/internal/plugin/installer/installer_test.go +++ b/internal/plugin/installer/installer_test.go @@ -15,33 +15,27 @@ limitations under the License. package installer -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestIsRemoteHTTPArchive(t *testing.T) { srv := mockArchiveServer() defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if isRemoteHTTPArchive("/not/a/URL") { - t.Error("Expected non-URL to return false") - } + assert.False(t, isRemoteHTTPArchive("/not/a/URL"), "Expected non-URL to return false") // URLs with valid archive extensions are considered valid archives // even if the server is unreachable (optimization to avoid unnecessary HTTP requests) - if !isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.tgz") { - t.Error("URL with .tgz extension should be considered a valid archive") - } + assert.True(t, isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.tgz"), "URL with .tgz extension should be considered a valid archive") // Test with invalid extension and unreachable server - if isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.notanarchive") { - t.Error("Bad URL without valid extension should not succeed") - } + assert.False(t, isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.notanarchive"), "Bad URL without valid extension should not succeed") - if !isRemoteHTTPArchive(source) { - t.Errorf("Expected %q to be a valid archive URL", source) - } + assert.True(t, isRemoteHTTPArchive(source), "Expected %q to be a valid archive URL", source) - if isRemoteHTTPArchive(source + "-not-an-extension") { - t.Error("Expected media type match to fail") - } + assert.False(t, isRemoteHTTPArchive(source+"-not-an-extension"), "Expected media type match to fail") } diff --git a/internal/plugin/installer/plugin_structure_test.go b/internal/plugin/installer/plugin_structure_test.go index 182eb9bd8..187918a4b 100644 --- a/internal/plugin/installer/plugin_structure_test.go +++ b/internal/plugin/installer/plugin_structure_test.go @@ -19,6 +19,9 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDetectPluginRoot(t *testing.T) { @@ -73,26 +76,18 @@ func TestDetectPluginRoot(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir := t.TempDir() - if err := tt.setup(dir); err != nil { - t.Fatalf("Setup failed: %v", err) - } + require.NoErrorf(t, tt.setup(dir), "Setup failed") root, err := detectPluginRoot(dir) if tt.expectError { - if err == nil { - t.Error("Expected error but got none") - } + assert.Error(t, err) } else { - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + require.NoError(t, err) expectedPath := dir if tt.expectRoot != "." { expectedPath = filepath.Join(dir, tt.expectRoot) } - if root != expectedPath { - t.Errorf("Expected root %s but got %s", expectedPath, root) - } + assert.Equal(t, expectedPath, root, "Expected root %s but got %s", expectedPath, root) } }) } @@ -145,20 +140,14 @@ description: test` for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir := t.TempDir() - if err := tt.setup(dir); err != nil { - t.Fatalf("Setup failed: %v", err) - } + require.NoErrorf(t, tt.setup(dir), "Setup failed") pluginRoot := filepath.Join(dir, tt.pluginRoot) err := validatePluginName(pluginRoot, tt.expectedName) if tt.expectError { - if err == nil { - t.Error("Expected error but got none") - } + assert.Error(t, err) } else { - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + assert.NoError(t, err) } }) } diff --git a/internal/plugin/installer/verification_test.go b/internal/plugin/installer/verification_test.go index d3824a0fc..1f8aa7ef4 100644 --- a/internal/plugin/installer/verification_test.go +++ b/internal/plugin/installer/verification_test.go @@ -23,6 +23,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" ) @@ -37,29 +40,20 @@ func TestInstallWithOptions_VerifyMissingProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled should fail when .prov is missing result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"}) // Should fail with a missing provenance error - if err == nil { - t.Fatal("Expected installation to fail when .prov file is missing and verification is enabled") - } - if !strings.Contains(err.Error(), "no provenance file") { - t.Errorf("Expected 'no provenance file' in error message, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when .prov file is missing, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail when .prov file is missing and verification is enabled") + require.ErrorContains(t, err, "no provenance file") + assert.Nil(t, result, "Expected nil verification result when .prov file is missing, got: %+v", result) // Plugin should NOT be installed - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails due to missing .prov") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails due to missing .prov") } func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) { @@ -72,25 +66,18 @@ func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification explicitly disabled should succeed without .prov result, err := InstallWithOptions(installer, Options{Verify: false}) - if err != nil { - t.Fatalf("Expected installation to succeed with --verify=false, got error: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result) - } + require.NoError(t, err, "Expected installation to succeed with --verify=false") + assert.Nil(t, result, "Expected nil verification result when verification is disabled, got: %+v", result) // Plugin should be installed - if _, err := os.Stat(installer.Path()); os.IsNotExist(err) { - t.Errorf("Plugin should be installed at %s", installer.Path()) - } + _, err = os.Stat(installer.Path()) + assert.Falsef(t, os.IsNotExist(err), "Plugin should be installed at %s", installer.Path()) } func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { @@ -110,9 +97,7 @@ func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled @@ -120,20 +105,13 @@ func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail due to invalid signature (empty keyring) but we test that it gets past the hash check - if err == nil { - t.Fatal("Expected installation to fail with empty keyring") - } - if !strings.Contains(err.Error(), "plugin verification failed") { - t.Errorf("Expected plugin verification failed error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with empty keyring") + require.ErrorContains(t, err, "plugin verification failed") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) // Plugin should not be installed due to verification failure - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails") } func TestInstallWithOptions_VerifyWithInvalidProvenance(t *testing.T) { @@ -154,32 +132,23 @@ func TestInstallWithOptions_VerifyWithInvalidProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled (should fail) result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with verification error - if err == nil { - t.Fatal("Expected installation with invalid .prov file to fail") - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation with invalid .prov file to fail") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) // Should contain verification failure message expectedError := "plugin verification failed" - if !strings.Contains(err.Error(), expectedError) { - t.Errorf("Expected error message '%s', got: %s", expectedError, err.Error()) - } + require.ErrorContains(t, err, expectedError) // Plugin should not be installed - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails") } func TestInstallWithOptions_NoVerifyRequested(t *testing.T) { @@ -192,26 +161,19 @@ func TestInstallWithOptions_NoVerifyRequested(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install without verification (should succeed without any verification) result, err := InstallWithOptions(installer, Options{Verify: false}) // Should succeed with no verification - if err != nil { - t.Fatalf("Expected installation without verification to succeed, got error: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result) - } + require.NoError(t, err, "Expected installation without verification to succeed") + assert.Nil(t, result, "Expected nil verification result when verification is disabled, got: %+v", result) // Plugin should be installed - if _, err := os.Stat(installer.Path()); os.IsNotExist(err) { - t.Errorf("Plugin should be installed at %s", installer.Path()) - } + _, err = os.Stat(installer.Path()) + assert.Falsef(t, os.IsNotExist(err), "Plugin should be installed at %s", installer.Path()) } func TestInstallWithOptions_VerifyDirectoryNotSupported(t *testing.T) { @@ -222,24 +184,16 @@ func TestInstallWithOptions_VerifyDirectoryNotSupported(t *testing.T) { // Create local installer for directory installer, err := NewLocalInstaller(pluginDir) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail (directories don't support verification) result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"}) // Should fail with verification not supported error - if err == nil { - t.Fatal("Expected installation to fail with verification not supported error") - } - if !strings.Contains(err.Error(), "--verify is only supported for plugin tarballs") { - t.Errorf("Expected verification not supported error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with verification not supported error") + require.ErrorContains(t, err, "--verify is only supported for plugin tarballs") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } func TestInstallWithOptions_VerifyMismatchedProvenance(t *testing.T) { @@ -261,24 +215,16 @@ func TestInstallWithOptions_VerifyMismatchedProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail due to hash mismatch result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with verification error - if err == nil { - t.Fatal("Expected installation to fail with hash mismatch") - } - if !strings.Contains(err.Error(), "plugin verification failed") { - t.Errorf("Expected plugin verification failed error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with hash mismatch") + require.ErrorContains(t, err, "plugin verification failed") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { @@ -291,9 +237,7 @@ func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { // Create a .prov file but make it inaccessible (simulate permission error) provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("test"), 0o000); err != nil { - t.Fatalf("Failed to create inaccessible provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte("test"), 0o000), "Failed to create inaccessible provenance file") defer os.Remove(provFile) // Create keyring @@ -302,27 +246,21 @@ func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail due to access error result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with access error (either at stat level or during verification) - if err == nil { - t.Fatal("Expected installation to fail with provenance file access error") - } + require.Error(t, err, "Expected installation to fail with provenance file access error") // The error could be either "failed to access provenance file" or "plugin verification failed" // depending on when the permission error occurs if !strings.Contains(err.Error(), "failed to access provenance file") && !strings.Contains(err.Error(), "plugin verification failed") { t.Errorf("Expected provenance file access or verification error, got: %v", err) } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } // Helper functions for test setup @@ -333,9 +271,7 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatalf("Failed to create plugin directory: %v", err) - } + require.NoErrorf(t, os.MkdirAll(pluginDir, 0o755), "Failed to create plugin directory") // Create plugin.yaml using the standardized v1 format pluginYaml := `apiVersion: v1 @@ -346,9 +282,7 @@ version: 1.0.0 runtimeConfig: platformCommand: - command: echo` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0o644); err != nil { - t.Fatalf("Failed to create plugin.yaml: %v", err) - } + require.NoErrorf(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0o644), "Failed to create plugin.yaml") return pluginDir } @@ -360,15 +294,10 @@ func createTarballFromPluginDir(t *testing.T, pluginDir string) string { tmpDir := filepath.Dir(pluginDir) tgzPath := filepath.Join(tmpDir, "test-plugin-1.0.0.tgz") tarFile, err := os.Create(tgzPath) - if err != nil { - t.Fatalf("Failed to create tarball file: %v", err) - } + require.NoError(t, err, "Failed to create tarball file") defer tarFile.Close() - if err := plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { - t.Fatalf("Failed to create tarball: %v", err) - } - + require.NoErrorf(t, plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile), "Failed to create tarball") return tgzPath } @@ -379,9 +308,7 @@ func createProvFile(t *testing.T, provFile, pluginTgz, hash string) { if hash == "" { // Calculate actual hash of the tarball for realistic testing data, err := os.ReadFile(pluginTgz) - if err != nil { - t.Fatalf("Failed to read tarball for hashing: %v", err) - } + require.NoError(t, err, "Failed to read tarball for hashing") hashSum := sha256.Sum256(data) hashStr = fmt.Sprintf("sha256:%x", hashSum) } else { @@ -404,9 +331,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { - t.Fatalf("Failed to create provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(provContent), 0o644), "Failed to create provenance file") } func createProvFileInvalidFormat(t *testing.T, provFile string) { @@ -414,9 +339,7 @@ func createProvFileInvalidFormat(t *testing.T, provFile string) { // Create an invalid provenance file (not PGP signed format) invalidProv := "This is not a valid PGP signed message" - if err := os.WriteFile(provFile, []byte(invalidProv), 0o644); err != nil { - t.Fatalf("Failed to create invalid provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(invalidProv), 0o644), "Failed to create invalid provenance file") } func createTestKeyring(t *testing.T) string { @@ -427,9 +350,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { - t.Fatalf("Failed to create test keyring: %v", err) - } + require.NoErrorf(t, os.WriteFile(keyringPath, []byte{}, 0o644), "Failed to create test keyring") return keyringPath } diff --git a/internal/plugin/runtime_extismv1_test.go b/internal/plugin/runtime_extismv1_test.go index 290d418ea..72a24d111 100644 --- a/internal/plugin/runtime_extismv1_test.go +++ b/internal/plugin/runtime_extismv1_test.go @@ -59,8 +59,7 @@ func buildLoadExtismPlugin(t *testing.T, dir string) pluginRaw { func TestRuntimeConfigExtismV1Validate(t *testing.T) { rc := RuntimeConfigExtismV1{} - err := rc.Validate() - assert.NoError(t, err, "expected no error for empty RuntimeConfigExtismV1") + assert.NoError(t, rc.Validate(), "expected no error for empty RuntimeConfigExtismV1") } func TestRuntimeExtismV1InvokePlugin(t *testing.T) { diff --git a/internal/plugin/subprocess_commands_test.go b/internal/plugin/subprocess_commands_test.go index 6aa0a7435..b2ac19c02 100644 --- a/internal/plugin/subprocess_commands_test.go +++ b/internal/plugin/subprocess_commands_test.go @@ -39,9 +39,7 @@ func TestPrepareCommand(t *testing.T) { cmd, args, err := PrepareCommands(platformCommand, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandExtraArgs(t *testing.T) { @@ -113,9 +111,7 @@ func TestPrepareCommands(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsExtraArgs(t *testing.T) { @@ -136,9 +132,7 @@ func TestPrepareCommandsExtraArgs(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, extraArgs, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, expectedArgs) { - t.Fatalf("Expected %v, got %v", expectedArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, expectedArgs), "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoArch(t *testing.T) { @@ -155,9 +149,7 @@ func TestPrepareCommandsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoOsNoArch(t *testing.T) { @@ -174,9 +166,7 @@ func TestPrepareCommandsNoOsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoMatch(t *testing.T) { @@ -216,9 +206,7 @@ func TestPrepareCommandsExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, expectedArgs) { - t.Fatalf("Expected %v, got %v", expectedArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, expectedArgs), "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoExpand(t *testing.T) { @@ -235,7 +223,5 @@ func TestPrepareCommandsNoExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, false, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) } diff --git a/internal/plugin/verify_test.go b/internal/plugin/verify_test.go index 5721e0414..4f5b26a97 100644 --- a/internal/plugin/verify_test.go +++ b/internal/plugin/verify_test.go @@ -44,11 +44,9 @@ func TestVerifyPlugin(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(tempDir, "verify-test-plugin") - err := os.MkdirAll(pluginDir, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) - err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create tarball tarballPath := filepath.Join(tempDir, "verify-test-plugin.tar.gz") @@ -64,10 +62,9 @@ func TestVerifyPlugin(t *testing.T) { // Sign the plugin with source directory signer, err := provenance.NewFromKeyring(testKeyFile, "helm-test") require.NoError(t, err) - err = signer.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, signer.DecryptKey(func(_ string) ([]byte, error) { return []byte(""), nil - }) - require.NoError(t, err) + })) // Read the tarball data tarballData, err := os.ReadFile(tarballPath) @@ -78,8 +75,7 @@ func TestVerifyPlugin(t *testing.T) { // Write the signature to .prov file provFile := tarballPath + ".prov" - err = os.WriteFile(provFile, []byte(sig), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(provFile, []byte(sig), 0o644)) // Read the files for verification archiveData, err := os.ReadFile(tarballPath) @@ -105,11 +101,9 @@ func TestVerifyPluginBadSignature(t *testing.T) { // Create a plugin tarball pluginDir := filepath.Join(tempDir, "bad-plugin") - err := os.MkdirAll(pluginDir, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) - err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) tarballPath := filepath.Join(tempDir, "bad-plugin.tar.gz") tarFile, err := os.Create(tarballPath) @@ -133,8 +127,7 @@ InvalidSignatureData -----END PGP SIGNATURE-----` provFile := tarballPath + ".prov" - err = os.WriteFile(provFile, []byte(badSig), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(provFile, []byte(badSig), 0o644)) // Read the files archiveData, err := os.ReadFile(tarballPath) @@ -153,8 +146,7 @@ func TestVerifyPluginMissingProvenance(t *testing.T) { tarballPath := filepath.Join(tempDir, "no-prov.tar.gz") // Create a minimal tarball - err := os.WriteFile(tarballPath, []byte("dummy"), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(tarballPath, []byte("dummy"), 0o644)) // Read the tarball data archiveData, err := os.ReadFile(tarballPath) From 668e7e580a01dbf66da0f620da6b980ee0cb4d80 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 090/161] chore(internal): refactor: convert tests to testify assert/require part 3 refactor: convert tests to testify assert/require in internal Signed-off-by: Matthieu MOREL --- internal/chart/v3/dependency_test.go | 10 +- .../chart/v3/lint/rules/chartfile_test.go | 53 ++-- internal/chart/v3/util/expand_test.go | 40 +-- internal/third_party/dep/fs/fs_test.go | 262 +++++------------- 4 files changed, 112 insertions(+), 253 deletions(-) diff --git a/internal/chart/v3/dependency_test.go b/internal/chart/v3/dependency_test.go index fcea19aea..54b9ed9da 100644 --- a/internal/chart/v3/dependency_test.go +++ b/internal/chart/v3/dependency_test.go @@ -17,6 +17,8 @@ package v3 import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestValidateDependency(t *testing.T) { @@ -35,10 +37,10 @@ func TestValidateDependency(t *testing.T) { } { dep.Alias = value res := dep.Validate() - if res != nil && !shouldFail { - t.Errorf("Failed on case %q", dep.Alias) - } else if res == nil && shouldFail { - t.Errorf("Expected failure for %q", dep.Alias) + if shouldFail { + assert.Errorf(t, res, "Expected failure for %q", dep.Alias) + } else { + assert.NoErrorf(t, res, "Failed on case %q", dep.Alias) } } } diff --git a/internal/chart/v3/lint/rules/chartfile_test.go b/internal/chart/v3/lint/rules/chartfile_test.go index 9ac4ce75e..0638589b6 100644 --- a/internal/chart/v3/lint/rules/chartfile_test.go +++ b/internal/chart/v3/lint/rules/chartfile_test.go @@ -52,24 +52,19 @@ func TestValidateChartYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingChartFilePath, os.ModePerm) defer os.Remove(nonExistingChartFilePath) - err := validateChartYamlNotDirectory(nonExistingChartFilePath) - assert.Error(t, err, "validateChartYamlNotDirectory to return a linter error, got no error") + assert.Error(t, validateChartYamlNotDirectory(nonExistingChartFilePath), "validateChartYamlNotDirectory to return a linter error, got no error") } func TestValidateChartYamlFormat(t *testing.T) { - err := validateChartYamlFormat(errors.New("Read error")) - require.Error(t, err, "validateChartYamlFormat to return a linter error, got no error") + require.Error(t, validateChartYamlFormat(errors.New("Read error")), "validateChartYamlFormat to return a linter error, got no error") - err = validateChartYamlFormat(nil) - assert.NoError(t, err, "validateChartYamlFormat to return no error, got a linter error") + assert.NoError(t, validateChartYamlFormat(nil), "validateChartYamlFormat to return no error, got a linter error") } func TestValidateChartName(t *testing.T) { - err := validateChartName(badChart) - require.Error(t, err, "validateChartName to return a linter error, got no error") + require.Error(t, validateChartName(badChart), "validateChartName to return a linter error, got no error") - err = validateChartName(badChartName) - assert.Error(t, err, "expected validateChartName to return a linter error for an invalid name, got no error") + assert.Error(t, validateChartName(badChartName), "expected validateChartName to return a linter error for an invalid name, got no error") } func TestValidateChartVersion(t *testing.T) { @@ -90,15 +85,13 @@ func TestValidateChartVersion(t *testing.T) { for i, test := range failTest { t.Run(strconv.Itoa(i), func(t *testing.T) { badChart.Version = test.Version - err := validateChartVersion(badChart) - require.ErrorContains(t, err, test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) + require.ErrorContains(t, validateChartVersion(badChart), test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) }) } for _, version := range successTest { badChart.Version = version - err := validateChartVersion(badChart) - assert.NoError(t, err, "validateChartVersion(%s) to return no error, got a linter error", version) + assert.NoError(t, validateChartVersion(badChart), "validateChartVersion(%s) to return no error, got a linter error", version) } } @@ -124,24 +117,20 @@ func TestValidateChartMaintainer(t *testing.T) { for _, test := range failTest { t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - require.ErrorContains(t, err, test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) + require.ErrorContains(t, validateChartMaintainer(badChart), test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) }) } for _, test := range successTest { t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - require.NoError(t, err, "validateChartMaintainer(%s, %s) to return no error", test.Name, test.Email) + require.NoError(t, validateChartMaintainer(badChart), "validateChartMaintainer(%s, %s) to return no error", test.Name, test.Email) }) } // Testing for an empty maintainer badChart.Maintainers = []*chart.Maintainer{nil} - err := validateChartMaintainer(badChart) - require.Error(t, err, "validateChartMaintainer did not return error for nil maintainer as expected") - assert.EqualError(t, err, "a maintainer entry is empty", "validateChartMaintainer returned unexpected error for nil maintainer") + assert.EqualError(t, validateChartMaintainer(badChart), "a maintainer entry is empty") } func TestValidateChartSources(t *testing.T) { @@ -150,15 +139,13 @@ func TestValidateChartSources(t *testing.T) { for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Sources = []string{test} - err := validateChartSources(badChart) - require.ErrorContains(t, err, "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) + require.ErrorContains(t, validateChartSources(badChart), "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) }) } for _, test := range successTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - assert.NoError(t, err, "validateChartSources(%s) to return no error", test) + assert.NoError(t, validateChartSources(badChart), "validateChartSources(%s) to return no error", test) } } @@ -168,19 +155,13 @@ func TestValidateChartIconPresence(t *testing.T) { Icon: "", } - err := validateChartIconPresence(testChart) - - require.Error(t, err, "validateChartIconPresence to return a linter error, got no error") - assert.ErrorContains(t, err, "icon is recommended", "expected %q", "icon is recommended") + assert.ErrorContains(t, validateChartIconPresence(testChart), "icon is recommended", "expected %q", "icon is recommended") }) t.Run("Icon present", func(t *testing.T) { testChart := &chart.Metadata{ Icon: "http://example.org/icon.png", } - - err := validateChartIconPresence(testChart) - - assert.NoError(t, err, "Unexpected error") + assert.NoError(t, validateChartIconPresence(testChart)) }) } @@ -190,15 +171,13 @@ func TestValidateChartIconURL(t *testing.T) { for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Icon = test - err := validateChartIconURL(badChart) - require.ErrorContains(t, err, "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) + require.ErrorContains(t, validateChartIconURL(badChart), "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) }) } for _, test := range successTest { badChart.Icon = test - err := validateChartIconURL(badChart) - assert.NoError(t, err, "validateChartIconURL(%s) to return no error", test) + assert.NoError(t, validateChartIconURL(badChart), "validateChartIconURL(%s) to return no error", test) } } diff --git a/internal/chart/v3/util/expand_test.go b/internal/chart/v3/util/expand_test.go index a7a756485..e6d66b74e 100644 --- a/internal/chart/v3/util/expand_test.go +++ b/internal/chart/v3/util/expand_test.go @@ -47,19 +47,19 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff fStat, err := f.Stat() require.NoError(t, err) - err = tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: filepath.Join(chartName, relPath), Mode: int64(fStat.Mode()), Size: fStat.Size(), - }) - require.NoError(t, err) + })) data, err := fs.ReadFile(dir, relPath) require.NoError(t, err) - tw.Write(data) + _, err = tw.Write(data) + require.NoError(t, err) } - err := fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { + require.NoError(t, fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr } @@ -71,13 +71,10 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff writeFile(path) return nil - }) - require.NoError(t, err) + })) - err = tw.Close() - require.NoError(t, err) - err = gw.Close() - require.NoError(t, err) + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) return &result } @@ -87,20 +84,18 @@ func TestExpand(t *testing.T) { reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, reader.Close()) }) - if err := Expand(dest, reader); err != nil { - t.Fatal(err) - } + require.NoError(t, Expand(dest, reader)) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) require.NoError(t, err) - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, dir.Close()) }) fis, err := dir.Readdir(0) require.NoError(t, err) @@ -137,8 +132,7 @@ func TestExpandError(t *testing.T) { archive := makeTestChartArchive(t, tt.chartName, tt.chartDir) dest := t.TempDir() - err := Expand(dest, archive) - assert.ErrorContains(t, err, tt.wantErr) + assert.ErrorContains(t, Expand(dest, archive), tt.wantErr) }) } } @@ -146,16 +140,12 @@ func TestExpandError(t *testing.T) { func TestExpandFile(t *testing.T) { dest := t.TempDir() - if err := ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz"); err != nil { - t.Fatal(err) - } + require.NoError(t, ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz")) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) require.NoError(t, err) - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) require.NoError(t, err) diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index 797890f9f..d777b6af4 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -32,54 +32,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package fs import ( - "errors" "os" "path/filepath" "runtime" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRenameWithFallback(t *testing.T) { dir := t.TempDir() - if err := RenameWithFallback(filepath.Join(dir, "does_not_exists"), filepath.Join(dir, "dst")); err == nil { - t.Fatal("expected an error for non existing file, but got nil") - } + require.Error(t, RenameWithFallback(filepath.Join(dir, "does_not_exists"), filepath.Join(dir, "dst")), "expected an error for non existing file, but got nil") srcpath := filepath.Join(dir, "src") - if srcf, err := os.Create(srcpath); err != nil { - t.Fatal(err) - } else { - srcf.Close() - } + srcf, err := os.Create(srcpath) + require.NoError(t, err) + srcf.Close() - if err := RenameWithFallback(srcpath, filepath.Join(dir, "dst")); err != nil { - t.Fatal(err) - } + require.NoError(t, RenameWithFallback(srcpath, filepath.Join(dir, "dst"))) srcpath = filepath.Join(dir, "a") - if err := os.MkdirAll(srcpath, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcpath, 0o777)) dstpath := filepath.Join(dir, "b") - if err := os.MkdirAll(dstpath, 0o777); err != nil { - t.Fatal(err) - } - - if err := RenameWithFallback(srcpath, dstpath); err == nil { - t.Fatal("expected an error if dst is an existing directory, but got nil") - } + require.NoError(t, os.MkdirAll(dstpath, 0o777)) + require.Error(t, RenameWithFallback(srcpath, dstpath), "expected an error if dst is an existing directory, but got nil") } func TestCopyDir(t *testing.T) { dir := t.TempDir() srcdir := filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) files := []struct { path string @@ -94,61 +81,40 @@ func TestCopyDir(t *testing.T) { for i, file := range files { fn := filepath.Join(srcdir, file.path) dn := filepath.Dir(fn) - if err := os.MkdirAll(dn, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(dn, 0o755)) fh, err := os.Create(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err = fh.WriteString(file.contents); err != nil { - t.Fatal(err) - } + _, err = fh.WriteString(file.contents) + require.NoError(t, err) fh.Close() files[i].fi, err = os.Stat(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } destdir := filepath.Join(dir, "dest") - if err := CopyDir(srcdir, destdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CopyDir(srcdir, destdir)) // Compare copy against structure indicated in 'files' for _, file := range files { fn := filepath.Join(srcdir, file.path) dn := filepath.Dir(fn) dirOK, err := IsDir(dn) - if err != nil { - t.Fatal(err) - } - if !dirOK { - t.Fatalf("expected %s to be a directory", dn) - } + require.NoError(t, err) + require.Truef(t, dirOK, "expected %s to be a directory", dn) got, err := os.ReadFile(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if file.contents != string(got) { - t.Fatalf("expected: %s, got: %s", file.contents, string(got)) - } + require.Equalf(t, file.contents, string(got), "expected: %s, got: %s", file.contents, string(got)) gotinfo, err := os.Stat(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if file.fi.Mode() != gotinfo.Mode() { - t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", - file.path, file.fi.Mode(), fn, gotinfo.Mode()) - } + require.Equalf(t, file.fi.Mode(), gotinfo.Mode(), "expected %s: %#v\n to be the same mode as %s: %#v", + file.path, file.fi.Mode(), fn, gotinfo.Mode()) } } @@ -178,9 +144,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) { dir := t.TempDir() dstdir = filepath.Join(dir, "dst") - if err := CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyDirFail_DstInaccessible(t *testing.T) { @@ -203,9 +167,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) cleanup := setupInaccessibleDir(t, func(dir string) error { dstdir = filepath.Join(dir, "dst") @@ -213,9 +175,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { }) defer cleanup() - if err := CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyDirFail_SrcIsNotDir(t *testing.T) { @@ -225,44 +185,25 @@ func TestCopyDirFail_SrcIsNotDir(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if _, err = os.Create(srcdir); err != nil { - t.Fatal(err) - } + _, err = os.Create(srcdir) + require.NoError(t, err) dstdir = filepath.Join(dir, "dst") - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } - - if !errors.Is(err, errSrcNotDir) { - t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errSrcNotDir, srcdir, dstdir, err) - } + require.ErrorIsf(t, CopyDir(srcdir, dstdir), errSrcNotDir, "expected %v error for CopyDir(%s, %s)", errSrcNotDir, srcdir, dstdir) } func TestCopyDirFail_DstExists(t *testing.T) { var srcdir, dstdir string - var err error dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err = os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) dstdir = filepath.Join(dir, "dst") - if err = os.MkdirAll(dstdir, 0o755); err != nil { - t.Fatal(err) - } - - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } - - if !errors.Is(err, errDstExist) { - t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errDstExist, srcdir, dstdir, err) - } + require.NoError(t, os.MkdirAll(dstdir, 0o755)) + require.ErrorIs(t, CopyDir(srcdir, dstdir), errDstExist, "expected %v error for CopyDir(%s, %s)", errDstExist, srcdir, dstdir) } func TestCopyDirFailOpen(t *testing.T) { @@ -288,70 +229,46 @@ func TestCopyDirFailOpen(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) srcfn := filepath.Join(srcdir, "file") srcf, err := os.Create(srcfn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) srcf.Close() // setup source file so that it cannot be read - if err = os.Chmod(srcfn, 0o222); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Chmod(srcfn, 0o222)) dstdir = filepath.Join(dir, "dst") - - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyFile(t *testing.T) { dir := t.TempDir() srcf, err := os.Create(filepath.Join(dir, "srcfile")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) want := "hello world" - if _, err := srcf.WriteString(want); err != nil { - t.Fatal(err) - } + _, err = srcf.WriteString(want) + require.NoError(t, err) srcf.Close() destf := filepath.Join(dir, "destf") - if err := CopyFile(srcf.Name(), destf); err != nil { - t.Fatal(err) - } + require.NoError(t, CopyFile(srcf.Name(), destf)) got, err := os.ReadFile(destf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if want != string(got) { - t.Fatalf("expected: %s, got: %s", want, string(got)) - } + require.Equalf(t, want, string(got), "expected: %s, got: %s", want, string(got)) wantinfo, err := os.Stat(srcf.Name()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) gotinfo, err := os.Stat(destf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if wantinfo.Mode() != gotinfo.Mode() { - t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), wantinfo.Mode(), destf, gotinfo.Mode()) - } + assert.Equalf(t, wantinfo.Mode(), gotinfo.Mode(), "expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), wantinfo.Mode(), destf, gotinfo.Mode()) } func TestCopyFileSymlink(t *testing.T) { @@ -366,9 +283,7 @@ func TestCopyFileSymlink(t *testing.T) { for symlink, dst := range testcases { t.Run(symlink, func(t *testing.T) { var err error - if err = CopyFile(symlink, dst); err != nil { - t.Fatalf("failed to copy symlink: %s", err) - } + require.NoErrorf(t, CopyFile(symlink, dst), "failed to copy symlink") var want, got string @@ -377,31 +292,21 @@ func TestCopyFileSymlink(t *testing.T) { // regular users aren't granted usually. So we copy the file // content as a fall back instead of creating a real symlink. srcb, err := os.ReadFile(symlink) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) dstb, err := os.ReadFile(dst) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) want = string(srcb) got = string(dstb) } else { want, err = os.Readlink(symlink) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) got, err = os.Readlink(dst) - if err != nil { - t.Fatalf("could not resolve symlink: %s", err) - } + require.NoErrorf(t, err, "could not resolve symlink") } - if want != got { - t.Fatalf("resolved path is incorrect. expected %s, got %s", want, got) - } + require.Equalf(t, want, got, "resolved path is incorrect. expected %s, got %s", want, got) }) } } @@ -424,9 +329,7 @@ func TestCopyFileFail(t *testing.T) { dir := t.TempDir() srcf, err := os.Create(filepath.Join(dir, "srcfile")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) srcf.Close() var dstdir string @@ -438,9 +341,7 @@ func TestCopyFileFail(t *testing.T) { defer cleanup() fn := filepath.Join(dstdir, "file") - if err := CopyFile(srcf.Name(), fn); err == nil { - t.Fatalf("expected error for %s, got none", fn) - } + require.Errorf(t, CopyFile(srcf.Name(), fn), "expected error for %s, got none", fn) } // setupInaccessibleDir creates a temporary location with a single @@ -463,9 +364,7 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() { subdir := filepath.Join(dir, "dir") cleanup := func() { - if err := os.Chmod(subdir, 0o777); err != nil { - t.Error(err) - } + assert.NoError(t, os.Chmod(subdir, 0o777)) } if err := os.Mkdir(subdir, 0o777); err != nil { @@ -498,9 +397,7 @@ func TestIsDir(t *testing.T) { } wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var dn string @@ -530,14 +427,16 @@ func TestIsDir(t *testing.T) { } for f, want := range tests { - got, err := IsDir(f) - if err != nil && !want.err { - t.Fatalf("expected no error, got %v", err) - } + t.Run(f, func(t *testing.T) { + got, err := IsDir(f) - if got != want.exists { - t.Fatalf("expected %t for %s, got %t", want.exists, f, got) - } + if want.err { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equalf(t, want.exists, got, "expected %t for %s, got %t", want.exists, f, got) + }) } } @@ -552,26 +451,18 @@ func TestIsSymlink(t *testing.T) { dir := t.TempDir() dirPath := filepath.Join(dir, "directory") - if err := os.MkdirAll(dirPath, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(dirPath, 0o777)) filePath := filepath.Join(dir, "file") f, err := os.Create(filePath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) f.Close() dirSymlink := filepath.Join(dir, "dirSymlink") fileSymlink := filepath.Join(dir, "fileSymlink") - if err = os.Symlink(dirPath, dirSymlink); err != nil { - t.Fatal(err) - } - if err = os.Symlink(filePath, fileSymlink); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(dirPath, dirSymlink)) + require.NoError(t, os.Symlink(filePath, fileSymlink)) var ( inaccessibleFile string @@ -609,14 +500,11 @@ func TestIsSymlink(t *testing.T) { for path, want := range tests { got, err := IsSymlink(path) - if err != nil { - if !want.err { - t.Errorf("expected no error, got %v", err) - } - } - - if got != want.expected { - t.Errorf("expected %t for %s, got %t", want.expected, path, got) + if want.err { + require.Error(t, err, "expected an error") + } else { + require.NoError(t, err, "expected no error") } + assert.Equalf(t, want.expected, got, "expected %t for %s, got %t", want.expected, path, got) } } From 6c45810119937e8fcbbc4f0b7f56c32a40c52d87 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 22:30:19 +0200 Subject: [PATCH 091/161] chore(internal): refactor: convert tests to testify assert/require part 4 (#32408) refactor: convert tests to testify assert/require in internal/chart/v3/util Signed-off-by: Matthieu MOREL --- internal/chart/v3/loader/load_test.go | 281 ++++++--------------- internal/chart/v3/util/create_test.go | 41 ++- internal/chart/v3/util/save_test.go | 32 +-- internal/plugin/runtime_subprocess_test.go | 4 +- internal/release/v2/info_test.go | 42 ++- 5 files changed, 121 insertions(+), 279 deletions(-) diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index 5caec7815..9378bcdf5 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -41,13 +41,9 @@ import ( func TestLoadDir(t *testing.T) { l, err := Loader("testdata/frobnitz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -60,33 +56,24 @@ func TestLoadDirWithDevNull(t *testing.T) { } l, err := Loader("testdata/frobnitz_with_dev_null") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } - if _, err := l.Load(); err == nil { - t.Error("packages with an irregular file (/dev/null) should not load") - } + require.NoError(t, err, "Failed to load testdata") + _, err = l.Load() + assert.Error(t, err, "packages with an irregular file (/dev/null) should not load") } func TestLoadDirWithSymlink(t *testing.T) { sym := filepath.Join("..", "LICENSE") link := filepath.Join("testdata", "frobnitz_with_symlink", "LICENSE") - if err := os.Symlink(sym, link); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(sym, link)) defer os.Remove(link) l, err := Loader("testdata/frobnitz_with_symlink") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -109,8 +96,7 @@ func TestBomTestData(t *testing.T) { defer unzipped.Close() for _, testFile := range testFiles { data := make([]byte, 3) - err := unzipped.Reset(bytes.NewReader(archive)) - require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") + require.NoErrorf(t, unzipped.Reset(bytes.NewReader(archive)), "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() @@ -132,13 +118,9 @@ func TestBomTestData(t *testing.T) { func TestLoadDirWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -148,13 +130,9 @@ func TestLoadDirWithUTFBOM(t *testing.T) { func TestLoadArchiveWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -164,13 +142,9 @@ func TestLoadArchiveWithUTFBOM(t *testing.T) { func TestLoadFile(t *testing.T) { l, err := Loader("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -224,36 +198,18 @@ icon: https://example.com/64x64.png } c, err := LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } - - if c.Name() != "frobnitz" { - t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Name()) - } - - if c.Values["var"] != "some values" { - t.Error("Expected chart values to be populated with default values") - } + require.NoError(t, err, "Expected good files to be loaded") + assert.Equal(t, "frobnitz", c.Name(), "Expected chart name to be 'frobnitz', got %s", c.Name()) + assert.Equal(t, "some values", c.Values["var"], "Expected chart values to be populated with default values") + assert.Len(t, c.Raw, 5, "Expected %d files, got %d", 5, len(c.Raw)) - if len(c.Raw) != 5 { - t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) - } + assert.True(t, bytes.Equal(c.Schema, []byte("type: Values")), "Expected chart schema to be populated with default values") - if !bytes.Equal(c.Schema, []byte("type: Values")) { - t.Error("Expected chart schema to be populated with default values") - } + assert.Len(t, c.Templates, 2, "Expected number of templates == 2, got %d", len(c.Templates)) - if len(c.Templates) != 2 { - t.Errorf("Expected number of templates == 2, got %d", len(c.Templates)) - } - - if _, err = LoadFiles([]*archive.BufferedFile{}); err == nil { - t.Fatal("Expected err to be non-nil") - } - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Expected chart metadata missing error, got '%s'", err.Error()) - } + _, err = LoadFiles([]*archive.BufferedFile{}) + require.Error(t, err, "Expected err to be non-nil") + assert.EqualError(t, err, "Chart.yaml file is missing", "Expected chart metadata missing error, got '%s'", err.Error()) } // Test the order of file loading. The Chart.yaml file needs to come first for @@ -309,9 +265,7 @@ icon: https://example.com/64x64.png // Capture stderr to make sure message about Chart.yaml handle dependencies // is not present r, w, err := os.Pipe() - if err != nil { - t.Fatalf("Unable to create pipe: %s", err) - } + require.NoError(t, err, "Unable to create pipe") stderr := log.Writer() log.SetOutput(w) defer func() { @@ -319,25 +273,19 @@ icon: https://example.com/64x64.png }() _, err = LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } + require.NoError(t, err, "Expected good files to be loaded") w.Close() var text bytes.Buffer io.Copy(&text, r) - if text.String() != "" { - t.Errorf("Expected no message to Stderr, got %s", text.String()) - } + assert.Empty(t, text.String(), "Expected no message to Stderr, got %s", text.String()) } // Packaging the chart on a Windows machine will produce an // archive that has \\ as delimiters. Test that we support these archives func TestLoadFileBackslash(t *testing.T) { c, err := Load("testdata/frobnitz_backslash-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyChartFileAndTemplate(t, c, "frobnitz_backslash") verifyChart(t, c) verifyDependencies(t, c) @@ -345,13 +293,9 @@ func TestLoadFileBackslash(t *testing.T) { func TestLoadV3WithReqs(t *testing.T) { l, err := Loader("testdata/frobnitz.v3.reqs") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } @@ -361,9 +305,7 @@ func TestLoadInvalidArchive(t *testing.T) { writeTar := func(filename, internalPath string, body []byte) { dest, err := os.Create(filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) zipper := gzip.NewWriter(dest) tw := tar.NewWriter(zipper) @@ -373,12 +315,9 @@ func TestLoadInvalidArchive(t *testing.T) { Size: int64(len(body)), ModTime: time.Now(), } - if err := tw.WriteHeader(h); err != nil { - t.Fatal(err) - } - if _, err := tw.Write(body); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(h)) + _, err = tw.Write(body) + require.NoError(t, err) tw.Close() zipper.Close() dest.Close() @@ -410,37 +349,27 @@ func TestLoadInvalidArchive(t *testing.T) { illegalChart := filepath.Join(tmpdir, tt.chartname) writeTar(illegalChart, tt.internal, []byte("hello: world")) _, err := Load(illegalChart) - if err == nil { - t.Fatal("expected error when unpacking illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) - } + require.Error(t, err, "expected error when unpacking illegal files") + require.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) } // Make sure that absolute path gets interpreted as relative illegalChart := filepath.Join(tmpdir, "abs-path.tgz") writeTar(illegalChart, "/Chart.yaml", []byte("hello: world")) _, err := Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + require.EqualError(t, err, "validation: chart.metadata.name is required") // And just to validate that the above was not spurious illegalChart = filepath.Join(tmpdir, "abs-path2.tgz") writeTar(illegalChart, "files/whatever.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Unexpected error message: %s", err) - } + require.EqualError(t, err, "Chart.yaml file is missing") // Finally, test that drive letter gets stripped off on Windows illegalChart = filepath.Join(tmpdir, "abs-winpath.tgz") writeTar(illegalChart, "c:\\Chart.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + assert.EqualError(t, err, "validation: chart.metadata.name is required") } func TestLoadValues(t *testing.T) { @@ -487,12 +416,8 @@ foo: for testName, testCase := range testCases { t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) - if err != nil { - tt.Fatal(err) - } - if !reflect.DeepEqual(values, testCase.expctedValues) { - tt.Errorf("Expected values: %v, got %v", testCase.expctedValues, values) - } + require.NoError(tt, err) + assert.Truef(tt, reflect.DeepEqual(values, testCase.expctedValues), "Expected values: %v, got %v", testCase.expctedValues, values) }) } } @@ -521,21 +446,15 @@ func TestMergeValuesV3(t *testing.T) { testMap := MergeMaps(flatMap, nestedMap) equal := reflect.DeepEqual(testMap, nestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) - } + assert.True(t, equal, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) equal = reflect.DeepEqual(testMap, flatMap) - if !equal { - t.Errorf("Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) - } + assert.True(t, equal, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) equal = reflect.DeepEqual(testMap, anotherNestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) - } + assert.True(t, equal, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -547,20 +466,14 @@ func TestMergeValuesV3(t *testing.T) { }, } equal = reflect.DeepEqual(testMap, expectedMap) - if !equal { - t.Errorf("Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) - } + assert.True(t, equal, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { t.Helper() - if c.Name() == "" { - t.Fatalf("No chart metadata found on %v", c) - } + require.NotEmpty(t, c.Name(), "No chart metadata found on %v", c) t.Logf("Verifying chart %s", c.Name()) - if len(c.Templates) != 1 { - t.Errorf("Expected 1 template, got %d", len(c.Templates)) - } + assert.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) numfiles := 6 if len(c.Files) != numfiles { @@ -587,62 +500,40 @@ func verifyChart(t *testing.T, c *chart.Chart) { } for _, dep := range c.Dependencies() { - if dep.Metadata == nil { - t.Fatalf("expected metadata on dependency: %v", dep) - } + require.NotNil(t, dep.Metadata, "expected metadata on dependency: %v", dep) exp, ok := expect[dep.Name()] - if !ok { - t.Fatalf("Unknown dependency %s", dep.Name()) - } - if exp["version"] != dep.Metadata.Version { - t.Errorf("Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) - } + require.True(t, ok, "Unknown dependency %s", dep.Name()) + assert.Equal(t, exp["version"], dep.Metadata.Version, "Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) } } func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } func verifyDependenciesLock(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } @@ -653,51 +544,25 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) { func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { t.Helper() - if c.Metadata == nil { - t.Fatal("Metadata is nil") - } - if c.Name() != name { - t.Errorf("Expected %s, got %s", name, c.Name()) - } - if len(c.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(c.Templates)) - } - if c.Templates[0].Name != "templates/template.tpl" { - t.Errorf("Unexpected template: %s", c.Templates[0].Name) - } - if len(c.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(c.Files) != 6 { - t.Fatalf("Expected 6 Files, got %d", len(c.Files)) - } - if len(c.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies())) - } - if len(c.Metadata.Dependencies) != 2 { - t.Fatalf("Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) - } - if len(c.Lock.Dependencies) != 2 { - t.Fatalf("Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) - } + require.NotNil(t, c.Metadata, "Metadata is nil") + assert.Equal(t, name, c.Name(), "Expected %s, got %s", name, c.Name()) + require.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) + assert.Equal(t, "templates/template.tpl", c.Templates[0].Name, "Unexpected template: %s", c.Templates[0].Name) + assert.NotEmpty(t, c.Templates[0].Data, "No template data.") + require.Len(t, c.Files, 6, "Expected 6 Files, got %d", len(c.Files)) + require.Len(t, c.Dependencies(), 2, "Expected 2 Dependency, got %d", len(c.Dependencies())) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Lock.Dependencies, 2, "Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) for _, dep := range c.Dependencies() { switch dep.Name() { case "mariner": case "alpine": - if len(dep.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(dep.Templates)) - } - if dep.Templates[0].Name != "templates/alpine-pod.yaml" { - t.Errorf("Unexpected template: %s", dep.Templates[0].Name) - } + require.Len(t, dep.Templates, 1, "Expected 1 template, got %d", len(dep.Templates)) + assert.Equal(t, "templates/alpine-pod.yaml", dep.Templates[0].Name, "Unexpected template: %s", dep.Templates[0].Name) assert.NotEmpty(t, dep.Templates[0].Data, "No template data.") - if len(dep.Files) != 1 { - t.Fatalf("Expected 1 Files, got %d", len(dep.Files)) - } - if len(dep.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies())) - } + require.Len(t, dep.Files, 1, "Expected 1 Files, got %d", len(dep.Files)) + require.Len(t, dep.Dependencies(), 2, "Expected 2 Dependency, got %d", len(dep.Dependencies())) default: t.Errorf("Unexpected dependency %s", dep.Name()) } @@ -707,8 +572,6 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { func verifyBomStripped(t *testing.T, files []*common.File) { t.Helper() for _, file := range files { - if bytes.HasPrefix(file.Data, utf8bom) { - t.Errorf("Byte Order Mark still present in processed file %s", file.Name) - } + assert.Falsef(t, bytes.HasPrefix(file.Data, utf8bom), "Byte Order Mark still present in processed file %s", file.Name) } } diff --git a/internal/chart/v3/util/create_test.go b/internal/chart/v3/util/create_test.go index eba0811ae..ddbbf6216 100644 --- a/internal/chart/v3/util/create_test.go +++ b/internal/chart/v3/util/create_test.go @@ -38,7 +38,7 @@ func TestCreate(t *testing.T) { dir := filepath.Join(tdir, "foo") mychart, err := loader.LoadDir(c) - require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) + require.NoError(t, err, "Failed to load newly created chart %q", c) assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) @@ -55,9 +55,8 @@ func TestCreate(t *testing.T) { TestConnectionName, ValuesfileName, } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + assert.NoErrorf(t, err, "Expected %s file", f) } } @@ -71,14 +70,12 @@ func TestCreateFrom(t *testing.T) { } srcdir := "./testdata/frobnitz/charts/mariner" - if err := CreateFrom(cf, tdir, srcdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CreateFrom(cf, tdir, srcdir)) dir := filepath.Join(tdir, "foo") c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) - require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) + require.NoError(t, err, "Failed to load newly created chart %q", c) assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) @@ -87,16 +84,13 @@ func TestCreateFrom(t *testing.T) { ValuesfileName, filepath.Join(TemplatesDir, "placeholder.tpl"), } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + require.NoErrorf(t, err, "Expected %s file", f) // Check each file to make sure has been replaced b, err := os.ReadFile(filepath.Join(dir, f)) - require.NoError(t, err, "Unable to read file %s: %s", f, err) - if bytes.Contains(b, []byte("")) { - t.Errorf("File %s contains ", f) - } + require.NoError(t, err, "Unable to read file %s", f) + assert.Falsef(t, bytes.Contains(b, []byte("")), "File %s contains ", f) } } @@ -106,9 +100,8 @@ func TestCreate_Overwrite(t *testing.T) { var errlog bytes.Buffer - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err := Create("foo", tdir) + require.NoError(t, err) dir := filepath.Join(tdir, "foo") @@ -117,9 +110,8 @@ func TestCreate_Overwrite(t *testing.T) { // Now re-run the create Stderr = &errlog - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err = Create("foo", tdir) + require.NoError(t, err) data, err := os.ReadFile(tplname) require.NoError(t, err) @@ -150,8 +142,11 @@ func TestValidateChartName(t *testing.T) { "abcdefghijklmnopqrstuvwxyz-_." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.": false, } { - if err := validateChartName(name); (err != nil) == shouldPass { - t.Errorf("test for %q failed", name) + err := validateChartName(name) + if shouldPass { + assert.NoErrorf(t, err, "Expected chart name %q to pass validation", name) + } else { + assert.Errorf(t, err, "Expected chart name %q to fail validation, but it passed", name) } } } diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index e729ad3b3..f7bd5dcfb 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -62,13 +62,9 @@ func TestSave(t *testing.T) { chartWithInvalidJSON := withSchema(*c, []byte("{")) where, err := Save(c, dest) - require.NoError(t, err, "Failed to save: %s", err) - if !strings.HasPrefix(where, dest) { - t.Fatalf("Expected %q to start with %q", where, dest) - } - if !strings.HasSuffix(where, ".tgz") { - t.Fatalf("Expected %q to end with .tgz", where) - } + require.NoError(t, err, "Failed to save") + require.Truef(t, strings.HasPrefix(where, dest), "Expected %q to start with %q", where, dest) + require.Truef(t, strings.HasSuffix(where, ".tgz"), "Expected %q to end with .tgz", where) c2, err := loader.LoadFile(where) require.NoError(t, err) @@ -83,13 +79,12 @@ func TestSave(t *testing.T) { formattedActual := Indent(indentation, string(c2.Schema)) t.Fatalf("Schema data did not match.\nExpected:\n%s\nActual:\n%s", formattedExpected, formattedActual) } - if _, err := Save(&chartWithInvalidJSON, dest); err == nil { - t.Fatal("Invalid JSON was not caught while saving chart") - } + _, err = Save(&chartWithInvalidJSON, dest) + require.Error(t, err, "Invalid JSON was not caught while saving chart") c.Metadata.APIVersion = chart.APIVersionV3 where, err = Save(c, dest) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") c2, err = loader.LoadFile(where) require.NoError(t, err) require.NotNil(t, c2.Lock, "Expected v3 chart archive to contain a Chart.lock file") @@ -152,16 +147,14 @@ func TestSavePreservesTimestamps(t *testing.T) { } where, err := Save(c, tmp) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - require.NoError(t, err, "Failed to parse tar: %v", err) + require.NoError(t, err, "Failed to parse tar") roundedTime := initialCreateTime.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(roundedTime) { - t.Fatalf("File timestamp not preserved: %v", header.ModTime) - } + require.Truef(t, header.ModTime.Equal(roundedTime), "File timestamp not preserved: %v", header.ModTime) } } @@ -235,8 +228,7 @@ func TestSaveDir(t *testing.T) { pth := filepath.Join(tmp2, "tmpcharts") require.NoError(t, os.MkdirAll(filepath.Join(pth), 0o755), "Failed to create directory") - err = SaveDir(c, pth) - assert.EqualError(t, err, "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) + assert.EqualError(t, SaveDir(c, pth), "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) } func TestRepeatableSave(t *testing.T) { @@ -297,10 +289,10 @@ func TestRepeatableSave(t *testing.T) { // create package dest := path.Join(tmp, "newdir") where, err := Save(test.chart, dest) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") // get shasum for package result, err := sha256Sum(where) - require.NoError(t, err, "Failed to check shasum: %s", err) + require.NoError(t, err, "Failed to check shasum") // assert that the package SHA is what we wanted. assert.Equal(t, test.want, result, "FormatName() result = %v, want %v", result, test.want) }) diff --git a/internal/plugin/runtime_subprocess_test.go b/internal/plugin/runtime_subprocess_test.go index c651dd3f7..c04127e0d 100644 --- a/internal/plugin/runtime_subprocess_test.go +++ b/internal/plugin/runtime_subprocess_test.go @@ -16,7 +16,6 @@ limitations under the License. package plugin import ( - "errors" "fmt" "os" "path/filepath" @@ -78,8 +77,7 @@ func TestSubprocessPluginRuntime(t *testing.T) { require.Error(t, err) ieerr := &InvokeExecError{} - ok := errors.As(err, &ieerr) - require.True(t, ok, "expected InvokeExecError, got %T", err) + require.ErrorAs(t, err, &ieerr, "expected InvokeExecError") assert.Equal(t, 56, ieerr.ExitCode) assert.Nil(t, output) diff --git a/internal/release/v2/info_test.go b/internal/release/v2/info_test.go index 5812c6560..571daa025 100644 --- a/internal/release/v2/info_test.go +++ b/internal/release/v2/info_test.go @@ -253,17 +253,17 @@ func TestInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) + assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) + assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) + assert.Equal(t, tt.expected.Description, info.Description) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Notes, info.Notes) + assert.Equal(t, tt.expected.Resources, info.Resources) } - require.NoError(t, err) - assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) - assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) - assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) - assert.Equal(t, tt.expected.Description, info.Description) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Notes, info.Notes) - assert.Equal(t, tt.expected.Resources, info.Resources) }) } } @@ -284,9 +284,7 @@ func TestInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, original.LastDeployed.Unix(), decoded.LastDeployed.Unix()) assert.Equal(t, original.Deleted.Unix(), decoded.Deleted.Unix()) @@ -330,8 +328,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, tt.info.RollbackRevision, decoded.RollbackRevision) assert.Equal(t, tt.info.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) @@ -342,8 +339,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { // Verify omitempty behavior: zero rollback_revision should not appear in JSON if tt.info.RollbackRevision == 0 { var raw map[string]any - err = json.Unmarshal(data, &raw) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &raw)) assert.NotContains(t, raw, "rollback_revision") } }) @@ -356,13 +352,12 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { input := `{"first_deployed":"","last_deployed":"","deleted":"","status":"deployed","description":"test"}` var info Info - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time fields are zero values - assert.True(t, info.FirstDeployed.IsZero()) - assert.True(t, info.LastDeployed.IsZero()) - assert.True(t, info.Deleted.IsZero()) + assert.Zero(t, info.FirstDeployed) + assert.Zero(t, info.LastDeployed) + assert.Zero(t, info.Deleted) assert.Equal(t, common.StatusDeployed, info.Status) assert.Equal(t, "test", info.Description) @@ -371,8 +366,7 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted due to omitzero tag assert.NotContains(t, result, "first_deployed") From 8c7f3a14d2cbde663847641b1f4274d266e6f0f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:09:32 -0600 Subject: [PATCH 092/161] chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#32411) Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-test.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/govulncheck.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 066adf1ce..9503674ed 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b0a03b342..d02d55b82 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index c5312e936..955f12002 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 0aee4c01c..0fae0be3a 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: persist-credentials: false - name: Add variables to environment file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3bed1e12a..2b2f93f4d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest-16-cores steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: fetch-depth: 0 @@ -85,7 +85,7 @@ jobs: if: github.ref == 'refs/heads/main' && github.repository == 'helm/helm' steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: fetch-depth: 0 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3a8410ced..41f97dd45 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false From df2d013517b0a237ea8858677558db3129a92911 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 093/161] chore(pkg): refactor: convert tests to testify assert/require part 3 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/chart/v2/util/chartfile_test.go | 107 +++------- pkg/repo/v1/index_test.go | 309 ++++++++-------------------- 2 files changed, 119 insertions(+), 297 deletions(-) diff --git a/pkg/chart/v2/util/chartfile_test.go b/pkg/chart/v2/util/chartfile_test.go index 068977eef..bdcb506da 100644 --- a/pkg/chart/v2/util/chartfile_test.go +++ b/pkg/chart/v2/util/chartfile_test.go @@ -19,6 +19,9 @@ package util import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" ) @@ -26,96 +29,44 @@ const testfile = "testdata/chartfiletest.yaml" func TestLoadChartfile(t *testing.T) { f, err := LoadChartfile(testfile) - if err != nil { - t.Errorf("Failed to open %s: %s", testfile, err) - return - } + require.NoErrorf(t, err, "Failed to open %s", testfile) verifyChartfile(t, f, "frobnitz") } func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { t.Helper() - if f == nil { - t.Fatal("Failed verifyChartfile because f is nil") - } - - if f.APIVersion != chart.APIVersionV1 { - t.Errorf("Expected API Version %q, got %q", chart.APIVersionV1, f.APIVersion) - } - - if f.Name != name { - t.Errorf("Expected %s, got %s", name, f.Name) - } - - if f.Description != "This is a frobnitz." { - t.Errorf("Unexpected description %q", f.Description) - } - - if f.Version != "1.2.3" { - t.Errorf("Unexpected version %q", f.Version) - } - - if len(f.Maintainers) != 2 { - t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers)) - } - - if f.Maintainers[0].Name != "The Helm Team" { - t.Error("Unexpected maintainer name.") - } - - if f.Maintainers[1].Email != "nobody@example.com" { - t.Error("Unexpected maintainer email.") - } - - if len(f.Sources) != 1 { - t.Fatal("Unexpected number of sources") - } - - if f.Sources[0] != "https://example.com/foo/bar" { - t.Errorf("Expected https://example.com/foo/bar, got %s", f.Sources) - } - - if f.Home != "http://example.com" { - t.Error("Unexpected home.") - } - - if f.Icon != "https://example.com/64x64.png" { - t.Errorf("Unexpected icon: %q", f.Icon) - } - - if len(f.Keywords) != 3 { - t.Error("Unexpected keywords") - } - - if len(f.Annotations) != 2 { - t.Fatal("Unexpected annotations") - } - - if want, got := "extravalue", f.Annotations["extrakey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } - - if want, got := "anothervalue", f.Annotations["anotherkey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } + require.NotNil(t, f, "Failed verifyChartfile because f is nil") + assert.Equal(t, chart.APIVersionV1, f.APIVersion, "Expected API Version %q, got %q", chart.APIVersionV1, f.APIVersion) + assert.Equal(t, name, f.Name, "Expected %s, got %s", name, f.Name) + assert.Equal(t, "This is a frobnitz.", f.Description, "Unexpected description %q", f.Description) + assert.Equal(t, "1.2.3", f.Version, "Unexpected version %q", f.Version) + assert.Len(t, f.Maintainers, 2, "Expected 2 maintainers, got %d", len(f.Maintainers)) + assert.Equal(t, "The Helm Team", f.Maintainers[0].Name, "Unexpected maintainer name.") + assert.Equal(t, "nobody@example.com", f.Maintainers[1].Email, "Unexpected maintainer email.") + require.Len(t, f.Sources, 1, "Unexpected number of sources") + assert.Equal(t, "https://example.com/foo/bar", f.Sources[0], "Expected https://example.com/foo/bar, got %s", f.Sources) + assert.Equal(t, "http://example.com", f.Home, "Unexpected home.") + assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) + assert.Len(t, f.Keywords, 3, "Unexpected keywords") + require.Len(t, f.Annotations, 2, "Unexpected annotations") + + want, got := "extravalue", f.Annotations["extrakey"] + assert.Equalf(t, want, got, "Want %q, but got %q", want, got) + + want, got = "anothervalue", f.Annotations["anotherkey"] + assert.Equalf(t, want, got, "Want %q, but got %q", want, got) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { - if kk[i] != k { - t.Errorf("Expected %q, got %q", kk[i], k) - } + assert.Equal(t, kk[i], k, "Expected %q, got %q", kk[i], k) } } func TestIsChartDir(t *testing.T) { validChartDir, err := IsChartDir("testdata/frobnitz") - if !validChartDir { - t.Errorf("unexpected error while reading chart-directory: (%v)", err) - return - } + require.NoError(t, err) + require.True(t, validChartDir, "expected valid chart directory") validChartDir, err = IsChartDir("testdata") - if validChartDir || err == nil { - t.Error("expected error but did not get any") - return - } + require.Error(t, err) + require.False(t, validChartDir, "expected invalid chart directory") } diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 126be125f..88aed14d7 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -28,6 +28,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/getter" @@ -95,33 +98,22 @@ func TestIndexFile(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "setter", Version: "0.1.8"}, "setter-0.1.8.tgz", "http://example.com/charts", "sha256:1234567890abc"}, {&chart.Metadata{APIVersion: "v2", Name: "setter", Version: "0.1.8+beta"}, "setter-0.1.8+beta.tgz", "http://example.com/charts", "sha256:1234567890abc"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error adding to index: %s", err) - } + require.NoErrorf(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "unexpected error adding to index") } i.SortEntries() - if i.APIVersion != APIVersionV1 { - t.Error("Expected API version v1") - } + assert.Equal(t, APIVersionV1, i.APIVersion, "Expected API version v1") - if len(i.Entries) != 3 { - t.Errorf("Expected 3 charts. Got %d", len(i.Entries)) - } + assert.Lenf(t, i.Entries, 3, "Expected 3 charts. Got %d", len(i.Entries)) - if i.Entries["clipper"][0].Name != "clipper" { - t.Errorf("Expected clipper, got %s", i.Entries["clipper"][0].Name) - } + assert.Equalf(t, "clipper", i.Entries["clipper"][0].Name, "Expected clipper, got %s", i.Entries["clipper"][0].Name) - if len(i.Entries["cutter"]) != 3 { - t.Error("Expected three cutters.") - } + assert.Len(t, i.Entries["cutter"], 3, "Expected three cutters.") // Test that the sort worked. 0.2 should be at the first index for Cutter. - if v := i.Entries["cutter"][0].Version; v != "0.2.0" { - t.Errorf("Unexpected first version: %s", v) - } + v := i.Entries["cutter"][0].Version + assert.Equalf(t, "0.2.0", v, "Unexpected first version: %s", v) cv, err := i.Get("setter", "0.1.9") if err == nil && !strings.Contains(cv.Version, "0.1.9") { @@ -129,14 +121,12 @@ func TestIndexFile(t *testing.T) { } cv, err = i.Get("setter", "0.1.9+alpha") - if err != nil || cv.Version != "0.1.9+alpha" { - t.Error("Expected version: 0.1.9+alpha") - } + require.NoError(t, err, "Expected version: 0.1.9+alpha") + assert.Equal(t, "0.1.9+alpha", cv.Version, "Expected version: 0.1.9+alpha") cv, err = i.Get("setter", "0.1.8") - if err != nil || cv.Version != "0.1.8" { - t.Error("Expected version: 0.1.8") - } + require.NoError(t, err, "Expected version: 0.1.8") + assert.Equal(t, "0.1.8", cv.Version, "Expected version: 0.1.8") } func TestLoadIndex(t *testing.T) { @@ -162,9 +152,7 @@ func TestLoadIndex(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { t.Parallel() i, err := LoadIndexFile(tc.Filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) }) } @@ -172,52 +160,39 @@ func TestLoadIndex(t *testing.T) { // TestLoadIndex_Duplicates is a regression to make sure that we don't non-deterministically allow duplicate packages. func TestLoadIndex_Duplicates(t *testing.T) { - if _, err := loadIndex([]byte(indexWithDuplicates), "indexWithDuplicates"); err == nil { - t.Error("Expected an error when duplicate entries are present") - } + _, err := loadIndex([]byte(indexWithDuplicates), "indexWithDuplicates") + assert.Error(t, err, "Expected an error when duplicate entries are present") } func TestLoadIndex_EmptyEntry(t *testing.T) { - if _, err := loadIndex([]byte(indexWithEmptyEntry), "indexWithEmptyEntry"); err != nil { - t.Errorf("unexpected error: %s", err) - } + _, err := loadIndex([]byte(indexWithEmptyEntry), "indexWithEmptyEntry") + assert.NoError(t, err) } func TestLoadIndex_Empty(t *testing.T) { - if _, err := loadIndex([]byte(""), "indexWithEmpty"); err == nil { - t.Error("Expected an error when index.yaml is empty.") - } + _, err := loadIndex([]byte(""), "indexWithEmpty") + assert.Error(t, err, "Expected an error when index.yaml is empty.") } func TestLoadIndexFileAnnotations(t *testing.T) { i, err := LoadIndexFile(annotationstestfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) - if len(i.Annotations) != 1 { - t.Fatalf("Expected 1 annotation but got %d", len(i.Annotations)) - } - if i.Annotations["helm.sh/test"] != "foo bar" { - t.Error("Did not get expected value for helm.sh/test annotation") - } + require.Lenf(t, i.Annotations, 1, "Expected 1 annotation but got %d", len(i.Annotations)) + assert.Equal(t, "foo bar", i.Annotations["helm.sh/test"], "Did not get expected value for helm.sh/test annotation") } func TestLoadUnorderedIndex(t *testing.T) { i, err := LoadIndexFile(unorderedTestfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) } func TestMerge(t *testing.T) { ind1 := NewIndexFile() - if err := ind1.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.1.0"}, "dreadnought-0.1.0.tgz", "http://example.com", "aaaa"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, ind1.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.1.0"}, "dreadnought-0.1.0.tgz", "http://example.com", "aaaa")) ind2 := NewIndexFile() @@ -230,121 +205,89 @@ func TestMerge(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.2.0"}, "dreadnought-0.2.0.tgz", "http://example.com", "aaaabbbb"}, {&chart.Metadata{APIVersion: "v2", Name: "doughnut", Version: "0.2.0"}, "doughnut-0.2.0.tgz", "http://example.com", "ccccbbbb"}, } { - if err := ind2.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error: %s", err) - } + require.NoError(t, ind2.MustAdd(x.md, x.filename, x.baseURL, x.digest)) } ind1.Merge(ind2) - if len(ind1.Entries) != 2 { - t.Errorf("Expected 2 entries, got %d", len(ind1.Entries)) - } + assert.Lenf(t, ind1.Entries, 2, "Expected 2 entries, got %d", len(ind1.Entries)) vs := ind1.Entries["dreadnought"] - if len(vs) != 2 { - t.Errorf("Expected 2 versions, got %d", len(vs)) - } + assert.Lenf(t, vs, 2, "Expected 2 versions, got %d", len(vs)) - if v := vs[1]; v.Version != "0.2.0" { - t.Errorf("Expected %q version to be 0.2.0, got %s", v.Name, v.Version) - } + v := vs[1] + assert.Equalf(t, "0.2.0", v.Version, "Expected %q version to be 0.2.0, got %s", v.Name, v.Version) } func TestDownloadIndexFile(t *testing.T) { t.Run("should download index file", func(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() r, err := NewChartRepository(&Entry{ Name: testRepo, URL: srv.URL, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Errorf("Problem creating chart repository from %s: %v", testRepo, err) - } + require.NoErrorf(t, err, "Problem creating chart repository from %s", testRepo) idx, err := r.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %#v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created index file: %#v", err) - } + _, err = os.Stat(idx) + + require.NoErrorf(t, err, "error finding created index file") i, err := LoadIndexFile(idx) - if err != nil { - t.Fatalf("Index %q failed to parse: %s", testfile, err) - } + require.NoErrorf(t, err, "Index %q failed to parse", testfile) verifyLocalIndex(t, i) // Check that charts file is also created idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created charts file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created charts file") b, err := os.ReadFile(idx) - if err != nil { - t.Fatalf("error reading charts file: %#v", err) - } + require.NoErrorf(t, err, "error reading charts file") verifyLocalChartsFile(t, b, i) }) t.Run("should not decode the path in the repo url while downloading index", func(t *testing.T) { chartRepoURLPath := "/some%2Fpath/test" fileBytes, err := os.ReadFile("testdata/local-index.yaml") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.RawPath == chartRepoURLPath+"/index.yaml" { w.Write(fileBytes) } }) srv, err := startLocalServerForTests(handler) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() r, err := NewChartRepository(&Entry{ Name: testRepo, URL: srv.URL + chartRepoURLPath, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Errorf("Problem creating chart repository from %s: %v", testRepo, err) - } + require.NoErrorf(t, err, "Problem creating chart repository from %s", testRepo) idx, err := r.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %#v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created index file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created index file") i, err := LoadIndexFile(idx) - if err != nil { - t.Fatalf("Index %q failed to parse: %s", testfile, err) - } + require.NoErrorf(t, err, "Index %q failed to parse", testfile) verifyLocalIndex(t, i) // Check that charts file is also created idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created charts file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created charts file") b, err := os.ReadFile(idx) - if err != nil { - t.Fatalf("error reading charts file: %#v", err) - } + require.NoErrorf(t, err, "error reading charts file") verifyLocalChartsFile(t, b, i) }) } @@ -352,18 +295,13 @@ func TestDownloadIndexFile(t *testing.T) { func verifyLocalIndex(t *testing.T, i *IndexFile) { t.Helper() numEntries := len(i.Entries) - if numEntries != 3 { - t.Errorf("Expected 3 entries in index file but got %d", numEntries) - } + assert.Equalf(t, 3, numEntries, "Expected 3 entries in index file but got %d", numEntries) alpine, ok := i.Entries["alpine"] - if !ok { - t.Fatal("'alpine' section not found.") - } + require.True(t, ok, "'alpine' section not found.") - if l := len(alpine); l != 1 { - t.Fatalf("'alpine' should have 1 chart, got %d", l) - } + l := len(alpine) + require.Equalf(t, 1, l, "'alpine' should have 1 chart, got %d", l) nginx, ok := i.Entries["nginx"] if !ok || len(nginx) != 2 { @@ -419,31 +357,17 @@ func verifyLocalIndex(t *testing.T, i *IndexFile) { for i, tt := range tests { expect := expects[i] - if tt.Name != expect.Name { - t.Errorf("Expected name %q, got %q", expect.Name, tt.Name) - } - if tt.Description != expect.Description { - t.Errorf("Expected description %q, got %q", expect.Description, tt.Description) - } - if tt.Version != expect.Version { - t.Errorf("Expected version %q, got %q", expect.Version, tt.Version) - } - if tt.Digest != expect.Digest { - t.Errorf("Expected digest %q, got %q", expect.Digest, tt.Digest) - } - if tt.Home != expect.Home { - t.Errorf("Expected home %q, got %q", expect.Home, tt.Home) - } + assert.Equalf(t, expect.Name, tt.Name, "Expected name %q, got %q", expect.Name, tt.Name) + assert.Equalf(t, expect.Description, tt.Description, "Expected description %q, got %q", expect.Description, tt.Description) + assert.Equalf(t, expect.Version, tt.Version, "Expected version %q, got %q", expect.Version, tt.Version) + assert.Equalf(t, expect.Digest, tt.Digest, "Expected digest %q, got %q", expect.Digest, tt.Digest) + assert.Equalf(t, expect.Home, tt.Home, "Expected home %q, got %q", expect.Home, tt.Home) for i, url := range tt.URLs { - if url != expect.URLs[i] { - t.Errorf("Expected URL %q, got %q", expect.URLs[i], url) - } + assert.Equalf(t, expect.URLs[i], url, "Expected URL %q, got %q", expect.URLs[i], url) } for i, kw := range tt.Keywords { - if kw != expect.Keywords[i] { - t.Errorf("Expected keywords %q, got %q", expect.Keywords[i], kw) - } + assert.Equalf(t, expect.Keywords[i], kw, "Expected keywords %q, got %q", expect.Keywords[i], kw) } } } @@ -462,21 +386,16 @@ func verifyLocalChartsFile(t *testing.T, chartsContent []byte, indexContent *Ind } sort.Strings(reald) - if strings.Join(expected, " ") != strings.Join(reald, " ") { - t.Errorf("Cached charts file content unexpected. Expected:\n%s\ngot:\n%s", expected, reald) - } + assert.Equalf(t, strings.Join(expected, " "), strings.Join(reald, " "), "Cached charts file content unexpected. Expected:\n%s\ngot:\n%s", expected, reald) } func TestIndexDirectory(t *testing.T) { dir := "testdata/repository" index, err := IndexDirectory(dir, "http://localhost:8080") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if l := len(index.Entries); l != 3 { - t.Fatalf("Expected 3 entries, got %d", l) - } + l := len(index.Entries) + require.Equalf(t, 3, l, "Expected 3 entries, got %d", l) // Other things test the entry generation more thoroughly. We just test a // few fields. @@ -489,20 +408,12 @@ func TestIndexDirectory(t *testing.T) { for _, test := range corpus { cname := test.chartName frobs, ok := index.Entries[cname] - if !ok { - t.Fatalf("Could not read chart %s", cname) - } + require.Truef(t, ok, "Could not read chart %s", cname) frob := frobs[0] - if frob.Digest == "" { - t.Errorf("Missing digest of file %s.", frob.Name) - } - if frob.URLs[0] != test.downloadLink { - t.Errorf("Unexpected URLs: %v", frob.URLs) - } - if frob.Name != cname { - t.Errorf("Expected %q, got %q", cname, frob.Name) - } + assert.NotEmptyf(t, frob.Digest, "Missing digest of file %s.", frob.Name) + assert.Equalf(t, test.downloadLink, frob.URLs[0], "Unexpected URLs: %v", frob.URLs) + assert.Equalf(t, cname, frob.Name, "Expected %q, got %q", cname, frob.Name) } } @@ -520,64 +431,40 @@ func TestIndexAdd(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "alpine", Version: "0.1.0"}, "/home/charts/alpine-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"}, {&chart.Metadata{APIVersion: "v2", Name: "deis", Version: "0.1.0"}, "/home/charts/deis-0.1.0.tgz", "http://example.com/charts/", "sha256:1234567890"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error adding to index: %s", err) - } + require.NoErrorf(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "unexpected error adding to index") } - if i.Entries["clipper"][0].URLs[0] != "http://example.com/charts/clipper-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/clipper-0.1.0.tgz, got %s", i.Entries["clipper"][0].URLs[0]) - } - if i.Entries["alpine"][0].URLs[0] != "http://example.com/charts/alpine-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/alpine-0.1.0.tgz, got %s", i.Entries["alpine"][0].URLs[0]) - } - if i.Entries["deis"][0].URLs[0] != "http://example.com/charts/deis-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/deis-0.1.0.tgz, got %s", i.Entries["deis"][0].URLs[0]) - } + assert.Equalf(t, "http://example.com/charts/clipper-0.1.0.tgz", i.Entries["clipper"][0].URLs[0], "Expected http://example.com/charts/clipper-0.1.0.tgz, got %s", i.Entries["clipper"][0].URLs[0]) + assert.Equalf(t, "http://example.com/charts/alpine-0.1.0.tgz", i.Entries["alpine"][0].URLs[0], "Expected http://example.com/charts/alpine-0.1.0.tgz, got %s", i.Entries["alpine"][0].URLs[0]) + assert.Equalf(t, "http://example.com/charts/deis-0.1.0.tgz", i.Entries["deis"][0].URLs[0], "Expected http://example.com/charts/deis-0.1.0.tgz, got %s", i.Entries["deis"][0].URLs[0]) // test error condition - if err := i.MustAdd(&chart.Metadata{}, "error-0.1.0.tgz", "", ""); err == nil { - t.Fatal("expected error adding to index") - } + require.Error(t, i.MustAdd(&chart.Metadata{}, "error-0.1.0.tgz", "", ""), "expected error adding to index") } func TestIndexWrite(t *testing.T) { i := NewIndexFile() - if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890")) dir := t.TempDir() testpath := filepath.Join(dir, "test") i.WriteFile(testpath, 0o600) got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } - if !strings.Contains(string(got), "clipper-0.1.0.tgz") { - t.Fatal("Index files doesn't contain expected content") - } + require.NoError(t, err) + require.Contains(t, string(got), "clipper-0.1.0.tgz", "Index files doesn't contain expected content") } func TestIndexJSONWrite(t *testing.T) { i := NewIndexFile() - if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890")) dir := t.TempDir() testpath := filepath.Join(dir, "test") i.WriteJSONFile(testpath, 0o600) got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } - if !json.Valid(got) { - t.Fatal("Index files doesn't contain valid JSON") - } - if !strings.Contains(string(got), "clipper-0.1.0.tgz") { - t.Fatal("Index files doesn't contain expected content") - } + require.NoError(t, err) + require.True(t, json.Valid(got), "Index files doesn't contain valid JSON") + require.Contains(t, string(got), "clipper-0.1.0.tgz", "Index files doesn't contain expected content") } func TestAddFileIndexEntriesNil(t *testing.T) { @@ -592,9 +479,7 @@ func TestAddFileIndexEntriesNil(t *testing.T) { }{ {&chart.Metadata{APIVersion: "v2", Name: " ", Version: "8033-5.apinie+s.r"}, "setter-0.1.9+beta.tgz", "http://example.com/charts", "sha256:1234567890abc"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err == nil { - t.Error("expected err to be non-nil when entries not initialized") - } + assert.Error(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "expected err to be non-nil when entries not initialized") } } @@ -624,22 +509,16 @@ func TestIgnoreSkippableChartValidationError(t *testing.T) { result := ignoreSkippableChartValidationError(tc.Input) if tc.Input == nil { - if result != nil { - t.Error("expected nil result for nil input") - } + assert.NoError(t, result, "expected nil result for nil input") return } if tc.ErrorSkipped { - if result != nil { - t.Error("expected nil result for skipped error") - } + assert.NoError(t, result, "expected nil result for skipped error") return } - if !errors.Is(tc.Input, result) { - t.Error("expected the result equal to input") - } + assert.ErrorIs(t, tc.Input, result, "expected the result equal to input") }) } } @@ -700,17 +579,11 @@ func TestLoadIndex_DuplicateChartDeps(t *testing.T) { for _, tc := range tests { t.Run(tc.source, func(t *testing.T) { idx, err := loadIndex([]byte(tc.data), tc.source) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) cvs := idx.Entries["nginx"] - if cvs == nil { - t.Error("expected one chart version not to be filtered out") - } + assert.NotNil(t, cvs, "expected one chart version not to be filtered out") for _, v := range cvs { - if v.Name == "alpine" { - t.Error("malformed version was not filtered out") - } + assert.NotEqual(t, "alpine", v.Name, "malformed version was not filtered out") } }) } @@ -751,9 +624,7 @@ func TestIsVersionRange(t *testing.T) { for _, tt := range tests { t.Run(tt.version, func(t *testing.T) { got := isVersionRange(tt.version) - if got != tt.expected { - t.Errorf("isVersionRange(%q) = %v, want %v", tt.version, got, tt.expected) - } + assert.Equalf(t, tt.expected, got, "isVersionRange(%q) = %v, want %v", tt.version, got, tt.expected) }) } } From 658a8fac156a92a7462cc9aab98da796da6dc116 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 094/161] chore(pkg): refactor: convert tests to testify assert/require part 4 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/chart/v2/loader/load_test.go | 322 ++++++++---------------------- pkg/storage/driver/memory_test.go | 93 +++------ 2 files changed, 116 insertions(+), 299 deletions(-) diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index 46d17e899..da5c3b725 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -31,6 +31,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" @@ -40,13 +41,9 @@ import ( func TestLoadDir(t *testing.T) { l, err := Loader("testdata/frobnitz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -59,33 +56,24 @@ func TestLoadDirWithDevNull(t *testing.T) { } l, err := Loader("testdata/frobnitz_with_dev_null") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } - if _, err := l.Load(); err == nil { - t.Error("packages with an irregular file (/dev/null) should not load") - } + require.NoError(t, err, "Failed to load testdata") + _, err = l.Load() + assert.Error(t, err, "packages with an irregular file (/dev/null) should not load") } func TestLoadDirWithSymlink(t *testing.T) { sym := filepath.Join("..", "LICENSE") link := filepath.Join("testdata", "frobnitz_with_symlink", "LICENSE") - if err := os.Symlink(sym, link); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(sym, link)) defer os.Remove(link) l, err := Loader("testdata/frobnitz_with_symlink") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -102,18 +90,13 @@ func TestBomTestData(t *testing.T) { } archive, err := os.ReadFile("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoError(t, err, "Error reading archive frobnitz_with_bom.tgz") unzipped, err := gzip.NewReader(bytes.NewReader(archive)) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoError(t, err, "Error reading archive frobnitz_with_bom.tgz") defer unzipped.Close() for _, testFile := range testFiles { data := make([]byte, 3) - err := unzipped.Reset(bytes.NewReader(archive)) - require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") + require.NoErrorf(t, unzipped.Reset(bytes.NewReader(archive)), "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() @@ -135,13 +118,9 @@ func TestBomTestData(t *testing.T) { func TestLoadDirWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -151,13 +130,9 @@ func TestLoadDirWithUTFBOM(t *testing.T) { func TestLoadArchiveWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -167,39 +142,27 @@ func TestLoadArchiveWithUTFBOM(t *testing.T) { func TestLoadV1(t *testing.T) { l, err := Loader("testdata/frobnitz.v1") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } func TestLoadFileV1(t *testing.T) { l, err := Loader("testdata/frobnitz.v1.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } func TestLoadFile(t *testing.T) { l, err := Loader("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -223,12 +186,8 @@ func TestLoadFiles_BadCases(t *testing.T) { expectError: "validation: chart.metadata.apiVersion is required"}, } { _, err := LoadFiles(tt.bufferedFiles) - if err == nil { - t.Fatal("expected error when load illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.name) - } + require.Error(t, err, "expected error when load illegal files") + assert.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.name) } } @@ -280,36 +239,16 @@ icon: https://example.com/64x64.png } c, err := LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } - - if c.Name() != "frobnitz" { - t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Name()) - } - - if c.Values["var"] != "some values" { - t.Error("Expected chart values to be populated with default values") - } - - if len(c.Raw) != 5 { - t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) - } - - if !bytes.Equal(c.Schema, []byte("type: Values")) { - t.Error("Expected chart schema to be populated with default values") - } - - if len(c.Templates) != 2 { - t.Errorf("Expected number of templates == 2, got %d", len(c.Templates)) - } - - if _, err = LoadFiles([]*archive.BufferedFile{}); err == nil { - t.Fatal("Expected err to be non-nil") - } - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Expected chart metadata missing error, got '%s'", err.Error()) - } + require.NoError(t, err, "Expected good files to be loaded") + assert.Equal(t, "frobnitz", c.Name(), "Expected chart name to be 'frobnitz', got %s", c.Name()) + assert.Equal(t, "some values", c.Values["var"], "Expected chart values to be populated with default values") + assert.Len(t, c.Raw, 5, "Expected %d files, got %d", 5, len(c.Raw)) + assert.True(t, bytes.Equal(c.Schema, []byte("type: Values")), "Expected chart schema to be populated with default values") + assert.Len(t, c.Templates, 2, "Expected number of templates == 2, got %d", len(c.Templates)) + + _, err = LoadFiles([]*archive.BufferedFile{}) + require.Error(t, err, "Expected err to be non-nil") + assert.EqualError(t, err, "Chart.yaml file is missing") } // Test the order of file loading. The Chart.yaml file needs to come first for @@ -365,9 +304,7 @@ icon: https://example.com/64x64.png // Capture stderr to make sure message about Chart.yaml handle dependencies // is not present r, w, err := os.Pipe() - if err != nil { - t.Fatalf("Unable to create pipe: %s", err) - } + require.NoError(t, err, "Unable to create pipe") stderr := log.Writer() log.SetOutput(w) defer func() { @@ -375,25 +312,19 @@ icon: https://example.com/64x64.png }() _, err = LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } + require.NoError(t, err, "Expected good files to be loaded") w.Close() var text bytes.Buffer io.Copy(&text, r) - if text.String() != "" { - t.Errorf("Expected no message to Stderr, got %s", text.String()) - } + assert.Empty(t, text.String(), "Expected no message to Stderr, got %s", text.String()) } // Packaging the chart on a Windows machine will produce an // archive that has \\ as delimiters. Test that we support these archives func TestLoadFileBackslash(t *testing.T) { c, err := Load("testdata/frobnitz_backslash-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyChartFileAndTemplate(t, c, "frobnitz_backslash") verifyChart(t, c) verifyDependencies(t, c) @@ -401,13 +332,9 @@ func TestLoadFileBackslash(t *testing.T) { func TestLoadV2WithReqs(t *testing.T) { l, err := Loader("testdata/frobnitz.v2.reqs") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } @@ -417,9 +344,7 @@ func TestLoadInvalidArchive(t *testing.T) { writeTar := func(filename, internalPath string, body []byte) { dest, err := os.Create(filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) zipper := gzip.NewWriter(dest) tw := tar.NewWriter(zipper) @@ -429,12 +354,9 @@ func TestLoadInvalidArchive(t *testing.T) { Size: int64(len(body)), ModTime: time.Now(), } - if err := tw.WriteHeader(h); err != nil { - t.Fatal(err) - } - if _, err := tw.Write(body); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(h)) + _, err = tw.Write(body) + require.NoError(t, err) tw.Close() zipper.Close() dest.Close() @@ -466,37 +388,27 @@ func TestLoadInvalidArchive(t *testing.T) { illegalChart := filepath.Join(tmpdir, tt.chartname) writeTar(illegalChart, tt.internal, []byte("hello: world")) _, err := Load(illegalChart) - if err == nil { - t.Fatal("expected error when unpacking illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) - } + require.Error(t, err, "expected error when unpacking illegal files") + require.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) } // Make sure that absolute path gets interpreted as relative illegalChart := filepath.Join(tmpdir, "abs-path.tgz") writeTar(illegalChart, "/Chart.yaml", []byte("hello: world")) _, err := Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + require.EqualError(t, err, "validation: chart.metadata.name is required") // And just to validate that the above was not spurious illegalChart = filepath.Join(tmpdir, "abs-path2.tgz") writeTar(illegalChart, "files/whatever.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Unexpected error message: %s", err) - } + require.EqualError(t, err, "Chart.yaml file is missing") // Finally, test that drive letter gets stripped off on Windows illegalChart = filepath.Join(tmpdir, "abs-winpath.tgz") writeTar(illegalChart, "c:\\Chart.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + assert.EqualError(t, err, "validation: chart.metadata.name is required") } func TestLoadValues(t *testing.T) { @@ -543,12 +455,8 @@ foo: for testName, testCase := range testCases { t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) - if err != nil { - tt.Fatal(err) - } - if !reflect.DeepEqual(values, testCase.expctedValues) { - tt.Errorf("Expected values: %v, got %v", testCase.expctedValues, values) - } + require.NoError(tt, err) + assert.Truef(t, reflect.DeepEqual(values, testCase.expctedValues), "Expected values: %v, got %v", testCase.expctedValues, values) }) } } @@ -577,21 +485,15 @@ func TestMergeValuesV2(t *testing.T) { testMap := MergeMaps(flatMap, nestedMap) equal := reflect.DeepEqual(testMap, nestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) - } + assert.True(t, equal, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) equal = reflect.DeepEqual(testMap, flatMap) - if !equal { - t.Errorf("Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) - } + assert.True(t, equal, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) equal = reflect.DeepEqual(testMap, anotherNestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) - } + assert.True(t, equal, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -603,20 +505,14 @@ func TestMergeValuesV2(t *testing.T) { }, } equal = reflect.DeepEqual(testMap, expectedMap) - if !equal { - t.Errorf("Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) - } + assert.True(t, equal, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { t.Helper() - if c.Name() == "" { - t.Fatalf("No chart metadata found on %v", c) - } + require.NotEmpty(t, c.Name(), "No chart metadata found on %v", c) t.Logf("Verifying chart %s", c.Name()) - if len(c.Templates) != 1 { - t.Errorf("Expected 1 template, got %d", len(c.Templates)) - } + assert.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) numfiles := 6 if len(c.Files) != numfiles { @@ -643,62 +539,40 @@ func verifyChart(t *testing.T, c *chart.Chart) { } for _, dep := range c.Dependencies() { - if dep.Metadata == nil { - t.Fatalf("expected metadata on dependency: %v", dep) - } + require.NotNil(t, dep.Metadata, "expected metadata on dependency: %v", dep) exp, ok := expect[dep.Name()] - if !ok { - t.Fatalf("Unknown dependency %s", dep.Name()) - } - if exp["version"] != dep.Metadata.Version { - t.Errorf("Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) - } + require.True(t, ok, "Unknown dependency %s", dep.Name()) + assert.Equal(t, dep.Metadata.Version, exp["version"], "Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) } } func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } func verifyDependenciesLock(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } @@ -709,53 +583,25 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) { func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { t.Helper() - if c.Metadata == nil { - t.Fatal("Metadata is nil") - } - if c.Name() != name { - t.Errorf("Expected %s, got %s", name, c.Name()) - } - if len(c.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(c.Templates)) - } - if c.Templates[0].Name != "templates/template.tpl" { - t.Errorf("Unexpected template: %s", c.Templates[0].Name) - } - if len(c.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(c.Files) != 6 { - t.Fatalf("Expected 6 Files, got %d", len(c.Files)) - } - if len(c.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies())) - } - if len(c.Metadata.Dependencies) != 2 { - t.Fatalf("Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) - } - if len(c.Lock.Dependencies) != 2 { - t.Fatalf("Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) - } + require.NotNil(t, c.Metadata, "Metadata is nil") + assert.Equal(t, name, c.Name(), "Expected %s, got %s", name, c.Name()) + require.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) + assert.Equal(t, "templates/template.tpl", c.Templates[0].Name, "Unexpected template: %s", c.Templates[0].Name) + assert.NotEmpty(t, c.Templates[0].Data, "No template data.") + require.Len(t, c.Files, 6, "Expected 6 Files, got %d", len(c.Files)) + require.Len(t, c.Dependencies(), 2, "Expected 2 Dependency, got %d", len(c.Dependencies())) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Lock.Dependencies, 2, "Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) for _, dep := range c.Dependencies() { switch dep.Name() { case "mariner": case "alpine": - if len(dep.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(dep.Templates)) - } - if dep.Templates[0].Name != "templates/alpine-pod.yaml" { - t.Errorf("Unexpected template: %s", dep.Templates[0].Name) - } - if len(dep.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(dep.Files) != 1 { - t.Fatalf("Expected 1 Files, got %d", len(dep.Files)) - } - if len(dep.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies())) - } + require.Len(t, dep.Templates, 1, "Expected 1 template, got %d", len(dep.Templates)) + assert.Equal(t, "templates/alpine-pod.yaml", dep.Templates[0].Name, "Unexpected template: %s", dep.Templates[0].Name) + assert.NotEmpty(t, dep.Templates[0].Data, "No template data.") + require.Len(t, dep.Files, 1, "Expected 1 Files, got %d", len(dep.Files)) + require.Len(t, dep.Dependencies(), 2, "Expected 2 Dependency, got %d", len(dep.Dependencies())) default: t.Errorf("Unexpected dependency %s", dep.Name()) } @@ -765,8 +611,6 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { func verifyBomStripped(t *testing.T, files []*common.File) { t.Helper() for _, file := range files { - if bytes.HasPrefix(file.Data, utf8bom) { - t.Errorf("Byte Order Mark still present in processed file %s", file.Name) - } + assert.Falsef(t, bytes.HasPrefix(file.Data, utf8bom), "Byte Order Mark still present in processed file %s", file.Name) } } diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 6040daf59..7a8d4cb3e 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -21,6 +21,7 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" @@ -29,9 +30,8 @@ import ( ) func TestMemoryName(t *testing.T) { - if mem := NewMemory(); mem.Name() != MemoryDriverName { - t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name()) - } + mem := NewMemory() + assert.Equalf(t, MemoryDriverName, mem.Name(), "Expected name to be %q, got %q", MemoryDriverName, mem.Name()) } func TestMemoryCreate(t *testing.T) { @@ -66,13 +66,12 @@ func TestMemoryCreate(t *testing.T) { for _, tt := range tests { key := testKey(tt.rls.Name, tt.rls.Version) rls := tt.rls + err := ts.Create(key, rls) - if err := ts.Create(key, rls); err != nil { - if !tt.err { - t.Fatalf("failed to create %q: %s", tt.desc, err) - } - } else if tt.err { - t.Fatalf("Did not get expected error for %q\n", tt.desc) + if tt.err { + require.Error(t, err, "Did not get expected error for %q\n", tt.desc) + } else { + require.NoError(t, err, "failed to create %q", tt.desc) } } } @@ -93,12 +92,11 @@ func TestMemoryGet(t *testing.T) { ts := tsFixtureMemory(t) for _, tt := range tests { ts.SetNamespace(tt.namespace) - if _, err := ts.Get(tt.key); err != nil { - if !tt.err { - t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) - } - } else if tt.err { - t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) + _, err := ts.Get(tt.key) + if tt.err { + require.Error(t, err, "Did not get expected error for %q '%s'\n", tt.desc, tt.key) + } else { + require.NoError(t, err, "Failed %q to get '%s'", tt.desc, tt.key) } } } @@ -113,12 +111,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed releases: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed releases") + assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) // list all superseded releases ssd, err := ts.List(func(rel release.Releaser) bool { @@ -126,12 +120,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded releases: %s", err) - } - if len(ssd) != 6 { - t.Errorf("Expected 6 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded releases") + assert.Len(t, ssd, 6, "Expected 6 superseded, got %d", len(ssd)) // list all deleted releases del, err := ts.List(func(rel release.Releaser) bool { @@ -139,12 +129,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted releases: %s", err) - } - if len(del) != 0 { - t.Errorf("Expected 0 deleted, got %d", len(del)) - } + require.NoError(t, err, "Failed to list deleted releases") + assert.Empty(t, del, "Expected 0 deleted, got %d", len(del)) } func TestMemoryQuery(t *testing.T) { @@ -172,13 +158,9 @@ func TestMemoryQuery(t *testing.T) { for _, tt := range tests { ts.SetNamespace(tt.namespace) l, err := ts.Query(tt.lbs) - if err != nil { - t.Fatalf("Failed to query: %s\n", err) - } + require.NoError(t, err, "Failed to query") - if tt.xlen != len(l) { - t.Fatalf("Expected %d results, actual %d\n", tt.xlen, len(l)) - } + require.Equal(t, len(l), tt.xlen, "Expected %d results, actual %d\n", tt.xlen, len(l)) } } @@ -217,23 +199,18 @@ func TestMemoryUpdate(t *testing.T) { ts := tsFixtureMemory(t) for _, tt := range tests { - if err := ts.Update(tt.key, tt.rls); err != nil { - if !tt.err { - t.Fatalf("Failed %q: %s\n", tt.desc, err) - } - continue - } else if tt.err { - t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) - } + err := ts.Update(tt.key, tt.rls) - ts.SetNamespace(tt.rls.Namespace) - r, err := ts.Get(tt.key) - if err != nil { - t.Fatalf("Failed to get: %s\n", err) - } + if tt.err { + require.Error(t, err, "Did not get expected error for %q '%s'\n", tt.desc, tt.key) + } else { + require.NoError(t, err, "Failed %q", tt.desc) + + ts.SetNamespace(tt.rls.Namespace) - if !reflect.DeepEqual(r, tt.rls) { - t.Fatalf("Expected %v, actual %v\n", tt.rls, r) + r, err := ts.Get(tt.key) + require.NoError(t, err, "Failed to get") + require.Truef(t, reflect.DeepEqual(r, tt.rls), "Expected %v, actual %v\n", tt.rls, r) } } } @@ -256,9 +233,7 @@ func TestMemoryDelete(t *testing.T) { ts := tsFixtureMemory(t) ts.SetNamespace("") start, err := ts.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Query failed: %s", err) - } + require.NoError(t, err, "Query failed") startLen := len(start) for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { @@ -280,9 +255,7 @@ func TestMemoryDelete(t *testing.T) { // Make sure that the deleted records are gone. ts.SetNamespace("") end, err := ts.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Query failed: %s", err) - } + require.NoError(t, err, "Query failed") endLen := len(end) if startLen-2 != endLen { From 3ff05c835ecb1bbf794089d309556dbc75778ef7 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 095/161] chore(pkg): refactor: convert tests to testify assert/require part 5 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/downloader/cache_test.go | 5 +- pkg/kube/client_test.go | 279 ++++++++++------------------------- pkg/repo/v1/repo_test.go | 100 ++++--------- 3 files changed, 109 insertions(+), 275 deletions(-) diff --git a/pkg/downloader/cache_test.go b/pkg/downloader/cache_test.go index 49a7adc5d..32f014727 100644 --- a/pkg/downloader/cache_test.go +++ b/pkg/downloader/cache_test.go @@ -105,10 +105,9 @@ func TestDiskCache_PutAndGet(t *testing.T) { t.Run("GetDirectory", func(t *testing.T) { dirKey := sha256.Sum256([]byte("i am a directory")) dirPath := cache.fileName(dirKey, CacheChart) - err := os.MkdirAll(dirPath, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(dirPath, 0o755)) - _, err = cache.Get(dirKey, CacheChart) + _, err := cache.Get(dirKey, CacheChart) assert.EqualError(t, err, "is a directory") }) } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 6421a2c2d..4d46d2692 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -316,9 +316,7 @@ func TestCreate(t *testing.T) { list, err := c.Build(objBody(&tc.Pods), false) require.NoError(t, err) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( list, @@ -487,7 +485,7 @@ func TestUpdate(t *testing.T) { data, err := io.ReadAll(req.Body) require.NoError(t, err) - assert.Equal(t, `{}`, string(data)) + assert.JSONEq(t, `{}`, string(data)) } return newResponse(http.StatusOK, &listTarget.Items[0]) @@ -622,15 +620,12 @@ func TestBuild(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Test for an invalid manifest infos, err := c.Build(tt.reader, false) - if err != nil && !tt.err { - t.Errorf("Got error message when no error should have occurred: %v", err) - } else if err != nil && strings.Contains(err.Error(), "--validate=false") { - t.Error("error message was not scrubbed") - } - - if len(infos) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(infos)) + if tt.err { + require.ErrorContains(t, err, "--validate=false", "error message was not scrubbed") + } else { + require.NoError(t, err, "Got error message when no error should have occurred") } + assert.Len(t, infos, tt.count, "expected %d result objects, got %d", tt.count, len(infos)) }) } } @@ -661,15 +656,12 @@ func TestBuildTable(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Test for an invalid manifest infos, err := c.BuildTable(tt.reader, false) - if err != nil && !tt.err { - t.Errorf("Got error message when no error should have occurred: %v", err) - } else if err != nil && strings.Contains(err.Error(), "--validate=false") { - t.Error("error message was not scrubbed") - } - - if len(infos) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(infos)) + if tt.err { + require.ErrorContains(t, err, "--validate=false", "error message was not scrubbed") + } else { + require.NoError(t, err, "Got error message when no error should have occurred") } + assert.Len(t, infos, tt.count, "expected %d result objects, got %d", tt.count, len(infos)) }) } } @@ -705,21 +697,17 @@ func TestPerform(t *testing.T) { c := newTestClient(t) infos, err := c.Build(tt.reader, false) - if err != nil && err.Error() != tt.errMessage { - t.Errorf("Error while building manifests: %v", err) + if err != nil { + require.EqualErrorf(t, err, tt.errMessage, "Error while building manifests") } err = perform(infos, fn) - if (err != nil) != tt.err { - t.Errorf("expected error: %v, got %v", tt.err, err) - } - if err != nil && err.Error() != tt.errMessage { - t.Errorf("expected error message: %v, got %v", tt.errMessage, err) + assert.Equal(t, tt.err, (err != nil), "expected error: %v", tt.err) + if err != nil { + require.EqualErrorf(t, err, tt.errMessage, "expected error message: %v, got %v", tt.errMessage, err) } - if len(results) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(results)) - } + assert.Len(t, results, tt.count, "expected %d result objects, got %d", tt.count, len(results)) }) } } @@ -771,9 +759,7 @@ func TestWait(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -785,32 +771,19 @@ func TestWait(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(&podList), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 3 { - t.Errorf("expected 3 resource created, got %d", len(result.Created)) - } - - if err := c.Wait(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } + require.NoError(t, err) + assert.Len(t, result.Created, 3, "expected 3 resource created, got %d", len(result.Created)) + require.NoErrorf(t, c.Wait(resources, time.Second*30), "expected wait without error") - if time.Since(*created) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) - } + assert.GreaterOrEqualf(t, time.Since(*created), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) } func TestWaitJob(t *testing.T) { @@ -832,9 +805,7 @@ func TestWaitJob(t *testing.T) { return newResponse(http.StatusOK, job) case p == "/namespaces/default/jobs" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -846,31 +817,17 @@ func TestWaitJob(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(job), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 1 { - t.Errorf("expected 1 resource created, got %d", len(result.Created)) - } - - if err := c.WaitWithJobs(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } - - if time.Since(*created) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) - } + require.NoError(t, err) + assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) + require.NoErrorf(t, c.WaitWithJobs(resources, time.Second*30), "expected wait without error") + assert.GreaterOrEqualf(t, time.Since(*created), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) } func TestWaitDelete(t *testing.T) { @@ -896,9 +853,7 @@ func TestWaitDelete(t *testing.T) { return newResponse(http.StatusOK, &pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -908,73 +863,46 @@ func TestWaitDelete(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(&pod), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 1 { - t.Errorf("expected 1 resource created, got %d", len(result.Created)) - } - if _, err := c.Delete(resources, metav1.DeletePropagationBackground); err != nil { - t.Fatal(err) - } - - if err := c.WaitForDelete(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } - - if time.Since(*deleted) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*deleted)) - } + require.NoError(t, err) + assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) + require.NoErrorf(t, c.WaitForDelete(resources, time.Second*30), "expected wait without error") + assert.GreaterOrEqualf(t, time.Since(*deleted), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*deleted)) } func TestReal(t *testing.T) { t.Skip("This is a live test, comment this line to run") c := New(nil) resources, err := c.Build(strings.NewReader(guestbookManifest), false) - if err != nil { - t.Fatal(err) - } - if _, err := c.Create(resources); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + _, err = c.Create(resources) + require.NoError(t, err) testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest c = New(nil) resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false) - if err != nil { - t.Fatal(err) - } - if _, err := c.Create(resources); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + _, err = c.Create(resources) + require.NoError(t, err) resources, err = c.Build(strings.NewReader(testEndpointManifest), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, errs := c.Delete(resources, metav1.DeletePropagationBackground); errs != nil { - t.Fatal(errs) - } + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // ensures that delete does not fail if a resource is not found - if _, errs := c.Delete(resources, metav1.DeletePropagationBackground); errs != nil { - t.Fatal(errs) - } + _, errs = c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) } func TestGetPodList(t *testing.T) { @@ -1004,10 +932,9 @@ func TestOutputContainerLogsForPodList(t *testing.T) { c := Client{Namespace: namespace, kubeClient: kubeClient} outBuffer := &bytes.Buffer{} outBufferFunc := func(_, _, _ string) io.Writer { return outBuffer } - err := c.OutputContainerLogsForPodList(&somePodList, namespace, outBufferFunc) clientAssertions := assert.New(t) req := require.New(t) - req.NoError(err) + req.NoError(c.OutputContainerLogsForPodList(&somePodList, namespace, outBufferFunc)) clientAssertions.Equal("fake logsfake logsfake logs", outBuffer.String()) } @@ -1247,23 +1174,11 @@ func (c createPatchTestCase) run(t *testing.T) { } patch, patchType, err := createPatch(c.original, targetInfo, c.threeWayMergeForUnstructured) - if err != nil { - t.Fatalf("Failed to create patch: %v", err) - } + require.NoError(t, err, "Failed to create patch") - if c.expectedPatch != string(patch) { - t.Errorf("Unexpected patch.\nTarget:\n%s\nOriginal:\n%s\nActual:\n%s\n\nExpected:\n%s\nGot:\n%s", - c.target, - c.original, - c.actual, - c.expectedPatch, - string(patch), - ) - } + assert.Equal(t, c.expectedPatch, string(patch), "Unexpected patch.\nTarget:\n%s\nOriginal:\n%s\nActual:\n%s\n\nExpected:\n%s\nGot:\n%s", c.target, c.original, c.actual, c.expectedPatch, string(patch)) - if patchType != types.MergePatchType { - t.Errorf("Expected patch type %s, got %s", types.MergePatchType, patchType) - } + assert.Equal(t, types.MergePatchType, patchType, "Expected patch type %s, got %s", types.MergePatchType, patchType) } func newTestCustomResourceData(metadata map[string]string, spec map[string]any) *unstructured.Unstructured { @@ -1438,12 +1353,8 @@ func TestIsReachableTwiceAfterClientCreationFailure(t *testing.T) { assertReachableErr := func(label string, err error) { t.Helper() - if err == nil { - t.Fatalf("%s: expected error, got nil", label) - } - if !errors.Is(err, refusedErr) { - t.Fatalf("%s: expected error wrapping %v, got %v", label, refusedErr, err) - } + require.Error(t, err, "%s: expected error, got nil", label) + require.ErrorIs(t, err, refusedErr) } assertReachableErr("first call", client.IsReachable()) @@ -1472,9 +1383,7 @@ func TestIsIncompatibleServerError(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - if got := isIncompatibleServerError(tc.Err); got != tc.Want { - t.Errorf("isIncompatibleServerError() = %v, want %v", got, tc.Want) - } + assert.Equalf(t, tc.Want, isIncompatibleServerError(tc.Err), "isIncompatibleServerError()") }) } } @@ -1926,9 +1835,7 @@ func TestClientWaitContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -1949,10 +1856,7 @@ func TestClientWaitContextCancellationLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 2, "expected 2 resources created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - require.Error(t, err) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled") } func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { @@ -1981,9 +1885,7 @@ func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, job) case p == "/namespaces/default/jobs" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2004,9 +1906,7 @@ func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.WaitWithJobs(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitWithJobs(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { @@ -2041,9 +1941,7 @@ func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, &pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2065,12 +1963,9 @@ func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - if _, err := c.Delete(resources, metav1.DeletePropagationBackground); err != nil { - t.Fatal(err) - } - - err = c.WaitForDelete(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) + assert.ErrorContains(t, c.WaitForDelete(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitContextNilDoesNotPanic(t *testing.T) { @@ -2100,9 +1995,7 @@ func TestClientWaitContextNilDoesNotPanic(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -2125,10 +2018,7 @@ func TestClientWaitContextNilDoesNotPanic(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - require.NoError(t, err) - + require.NoError(t, c.Wait(resources, time.Second*30)) assert.GreaterOrEqual(t, time.Since(*created), time.Second*2, "expected to wait at least 2 seconds") } @@ -2152,9 +2042,7 @@ func TestClientWaitContextPreCancelledLegacy(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2175,9 +2063,7 @@ func TestClientWaitContextPreCancelledLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled") } func TestClientWaitContextCancellationStatusWatcher(t *testing.T) { @@ -2202,8 +2088,7 @@ metadata: cancel() - err = c.Wait(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitWithJobsContextCancellationStatusWatcher(t *testing.T) { @@ -2228,8 +2113,7 @@ metadata: cancel() - err = c.WaitWithJobs(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitWithJobs(resources, time.Second*30), "context canceled") } func TestClientWaitForDeleteContextCancellationStatusWatcher(t *testing.T) { @@ -2259,8 +2143,7 @@ status: cancel() - err = c.WaitForDelete(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitForDelete(resources, time.Second*30), "context canceled") } // testStatusReader is a custom status reader for testing that returns a configurable status. @@ -2334,8 +2217,7 @@ metadata: // The pod has no Ready condition, but our custom reader returns CurrentStatus, // so the wait should succeed immediately without timeout. - err = c.Wait(resources, time.Second*3) - require.NoError(t, err) + require.NoError(t, c.Wait(resources, time.Second*3)) } func TestClientStatusReadersWithWaitWithJobs(t *testing.T) { @@ -2376,8 +2258,7 @@ metadata: // The job has no Complete condition, but our custom reader returns CurrentStatus, // so the wait should succeed immediately without timeout. - err = c.WaitWithJobs(resources, time.Second*3) - require.NoError(t, err) + require.NoError(t, c.WaitWithJobs(resources, time.Second*3)) } func createManifest(t *testing.T, manifest string, @@ -2385,12 +2266,10 @@ func createManifest(t *testing.T, manifest string, t.Helper() m := make(map[string]any) - err := yaml.Unmarshal([]byte(manifest), &m) - require.NoError(t, err) + require.NoError(t, yaml.Unmarshal([]byte(manifest), &m)) obj := &unstructured.Unstructured{Object: m} gvk := obj.GroupVersionKind() mapping, err := fakeMapper.RESTMapping(gvk.GroupKind(), gvk.Version) require.NoError(t, err) - err = fakeClient.Tracker().Create(mapping.Resource, obj, obj.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(mapping.Resource, obj, obj.GetNamespace())) } diff --git a/pkg/repo/v1/repo_test.go b/pkg/repo/v1/repo_test.go index 960635fc5..e3373fc49 100644 --- a/pkg/repo/v1/repo_test.go +++ b/pkg/repo/v1/repo_test.go @@ -18,8 +18,10 @@ package repo import ( "os" - "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const testRepositoriesFile = "testdata/repositories.yaml" @@ -37,24 +39,14 @@ func TestFile(t *testing.T) { }, ) - if len(rf.Repositories) != 2 { - t.Fatal("Expected 2 repositories") - } + require.Len(t, rf.Repositories, 2, "Expected 2 repositories") - if rf.Has("nosuchrepo") { - t.Error("Found nonexistent repo") - } - if !rf.Has("incubator") { - t.Error("incubator repo is missing") - } + assert.False(t, rf.Has("nosuchrepo"), "Found nonexistent repo") + assert.True(t, rf.Has("incubator"), "incubator repo is missing") stable := rf.Repositories[0] - if stable.Name != "stable" { - t.Error("stable is not named stable") - } - if stable.URL != "https://example.com/stable/charts" { - t.Error("Wrong URL for stable") - } + assert.Equal(t, "stable", stable.Name, "stable is not named stable") + assert.Equal(t, "https://example.com/stable/charts", stable.URL, "Wrong URL for stable") } func TestNewFile(t *testing.T) { @@ -71,22 +63,14 @@ func TestNewFile(t *testing.T) { ) file, err := LoadFile(testRepositoriesFile) - if err != nil { - t.Errorf("%q could not be loaded: %s", testRepositoriesFile, err) - } + require.NoErrorf(t, err, "%q could not be loaded", testRepositoriesFile) - if len(expects.Repositories) != len(file.Repositories) { - t.Fatalf("Unexpected repo data: %#v", file.Repositories) - } + require.Lenf(t, file.Repositories, len(expects.Repositories), "Unexpected repo data: %#v", file.Repositories) for i, expect := range expects.Repositories { got := file.Repositories[i] - if expect.Name != got.Name { - t.Errorf("Expected name %q, got %q", expect.Name, got.Name) - } - if expect.URL != got.URL { - t.Errorf("Expected url %q, got %q", expect.URL, got.URL) - } + assert.Equalf(t, expect.Name, got.Name, "Expected name %q, got %q", expect.Name, got.Name) + assert.Equalf(t, expect.URL, got.URL, "Expected url %q, got %q", expect.URL, got.URL) } } @@ -114,18 +98,12 @@ func TestRepoFile_Get(t *testing.T) { name := "second" entry := repo.Get(name) - if entry == nil { - t.Fatalf("Expected repo entry %q to be found", name) - } + require.NotNilf(t, entry, "Expected repo entry %q to be found", name) - if entry.URL != "https://example.com/second" { - t.Errorf("Expected repo URL to be %q but got %q", "https://example.com/second", entry.URL) - } + assert.Equalf(t, "https://example.com/second", entry.URL, "Expected repo URL to be %q but got %q", "https://example.com/second", entry.URL) entry = repo.Get("nonexistent") - if entry != nil { - t.Errorf("Got unexpected entry %+v", entry) - } + assert.Nilf(t, entry, "Got unexpected entry %+v", entry) } func TestRemoveRepository(t *testing.T) { @@ -143,14 +121,10 @@ func TestRemoveRepository(t *testing.T) { removeRepository := "stable" found := sampleRepository.Remove(removeRepository) - if !found { - t.Errorf("expected repository %s not found", removeRepository) - } + assert.Truef(t, found, "expected repository %s not found", removeRepository) found = sampleRepository.Has(removeRepository) - if found { - t.Errorf("repository %s not deleted", removeRepository) - } + assert.Falsef(t, found, "repository %s not deleted", removeRepository) } func TestUpdateRepository(t *testing.T) { @@ -170,18 +144,14 @@ func TestUpdateRepository(t *testing.T) { URL: "https://example.com/sample", }) - if !sampleRepository.Has(newRepoName) { - t.Errorf("expected repository %s not found", newRepoName) - } + assert.Truef(t, sampleRepository.Has(newRepoName), "expected repository %s not found", newRepoName) repoCount := len(sampleRepository.Repositories) sampleRepository.Update(&Entry{Name: newRepoName, URL: "https://example.com/sample", }) - if repoCount != len(sampleRepository.Repositories) { - t.Errorf("invalid number of repositories found %d, expected number of repositories %d", len(sampleRepository.Repositories), repoCount) - } + assert.Lenf(t, sampleRepository.Repositories, repoCount, "invalid number of repositories found %d, expected number of repositories %d", len(sampleRepository.Repositories), repoCount) } func TestWriteFile(t *testing.T) { @@ -198,31 +168,21 @@ func TestWriteFile(t *testing.T) { ) file, err := os.CreateTemp(t.TempDir(), "helm-repo") - if err != nil { - t.Errorf("failed to create test-file (%v)", err) - } + require.NoErrorf(t, err, "failed to create test-file") defer os.Remove(file.Name()) - if err := sampleRepository.WriteFile(file.Name(), 0o600); err != nil { - t.Errorf("failed to write file (%v)", err) - } + require.NoErrorf(t, sampleRepository.WriteFile(file.Name(), 0o600), "failed to write file") repos, err := LoadFile(file.Name()) - if err != nil { - t.Errorf("failed to load file (%v)", err) - } + require.NoErrorf(t, err, "failed to load file") for _, repo := range sampleRepository.Repositories { - if !repos.Has(repo.Name) { - t.Errorf("expected repository %s not found", repo.Name) - } + assert.Truef(t, repos.Has(repo.Name), "expected repository %s not found", repo.Name) } } func TestRepoNotExists(t *testing.T) { - if _, err := LoadFile("/this/path/does/not/exist.yaml"); err == nil { - t.Error("expected err to be non-nil when path does not exist") - } else if !strings.Contains(err.Error(), "couldn't load repositories file") { - t.Error("expected prompt `couldn't load repositories file`") - } + _, err := LoadFile("/this/path/does/not/exist.yaml") + require.Error(t, err, "expected err to be non-nil when path does not exist") + assert.ErrorContains(t, err, "couldn't load repositories file", "expected prompt `couldn't load repositories file`") } func TestRemoveRepositoryInvalidEntries(t *testing.T) { @@ -246,12 +206,8 @@ func TestRemoveRepositoryInvalidEntries(t *testing.T) { removeRepository := "stable" found := sampleRepository.Remove(removeRepository) - if !found { - t.Errorf("expected repository %s not found", removeRepository) - } + assert.Truef(t, found, "expected repository %s not found", removeRepository) found = sampleRepository.Has(removeRepository) - if found { - t.Errorf("repository %s not deleted", removeRepository) - } + assert.Falsef(t, found, "repository %s not deleted", removeRepository) } From 0844b3b8b513e1ae6787c44fc5cfd224bf86c573 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 096/161] chore(pkg): refactor: convert tests to testify assert/require part 6 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/chart/v2/util/dependencies_test.go | 281 +++++++------------------ pkg/registry/chart_test.go | 2 +- pkg/repo/v1/chartrepo_test.go | 127 ++++------- 3 files changed, 110 insertions(+), 300 deletions(-) diff --git a/pkg/chart/v2/util/dependencies_test.go b/pkg/chart/v2/util/dependencies_test.go index 40a17ac3a..2386d2c28 100644 --- a/pkg/chart/v2/util/dependencies_test.go +++ b/pkg/chart/v2/util/dependencies_test.go @@ -21,6 +21,7 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" @@ -31,9 +32,7 @@ import ( func loadChart(t *testing.T, path string) *chart.Chart { t.Helper() c, err := loader.Load(path) - if err != nil { - t.Fatalf("failed to load testdata: %s", err) - } + require.NoError(t, err, "failed to load testdata") return c } @@ -44,19 +43,11 @@ func TestLoadDependency(t *testing.T) { } check := func(deps []*chart.Dependency) { - if len(deps) != 2 { - t.Errorf("expected 2 dependencies, got %d", len(deps)) - } + assert.Len(t, deps, 2, "expected 2 dependencies, got %d", len(deps)) for i, tt := range tests { - if deps[i].Name != tt.Name { - t.Errorf("expected dependency named %q, got %q", tt.Name, deps[i].Name) - } - if deps[i].Version != tt.Version { - t.Errorf("expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) - } - if deps[i].Repository != tt.Repository { - t.Errorf("expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) - } + assert.Equal(t, tt.Name, deps[i].Name, "expected dependency named %q, got %q", tt.Name, deps[i].Name) + assert.Equal(t, tt.Version, deps[i].Version, "expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) + assert.Equal(t, tt.Repository, deps[i].Repository, "expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) } } c := loadChart(t, "testdata/frobnitz") @@ -119,18 +110,12 @@ func TestDependencyEnabled(t *testing.T) { for _, tc := range tests { c := loadChart(t, "testdata/subpop") t.Run(tc.name, func(t *testing.T) { - if err := processDependencyEnabled(c, tc.v, ""); err != nil { - t.Fatalf("error processing enabled dependencies %v", err) - } + require.NoErrorf(t, processDependencyEnabled(c, tc.v, ""), "error processing enabled dependencies") names := extractChartNames(c) - if len(names) != len(tc.e) { - t.Fatalf("slice lengths do not match got %v, expected %v", len(names), len(tc.e)) - } + require.Len(t, names, len(tc.e), "slice lengths do not match got %v, expected %v", len(names), len(tc.e)) for i := range names { - if names[i] != tc.e[i] { - t.Fatalf("slice values do not match got %v, expected %v", names, tc.e) - } + require.Equal(t, tc.e[i], names[i], "slice values do not match got %v, expected %v", names, tc.e) } }) } @@ -221,64 +206,44 @@ func TestProcessDependencyImportValues(t *testing.T) { e["SCBexported2A"] = "blaster" e["global.SC1exported2.all.SC1exported3"] = "SC1expstr" - if err := processDependencyImportValues(c, false); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, false), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v for key %q", s, vv, kk) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, s, vv, "failed to match imported float value %v with expected %v for key %q", s, vv, kk) case bool: - if b := strconv.FormatBool(pv); b != vv { - t.Errorf("failed to match imported bool value %v with expected %v for key %q", b, vv, kk) - } + b := strconv.FormatBool(pv) + assert.Equalf(t, b, vv, "failed to match imported bool value %v with expected %v for key %q", b, vv, kk) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q for key %q", pv, vv, kk) - } + assert.Equal(t, vv, pv, "failed to match imported string value %q with expected %q for key %q", pv, vv, kk) } } // Since this was processed with coalescing there should be no null values. // Here we verify that. _, err := cc.PathValue("ensurenull") - if err == nil { - t.Error("expect nil value not found but found it") - } + require.Error(t, err, "expect nil value not found but found it") var xerr common.ErrNoValue require.ErrorAs(t, err, &xerr, "expected an ErrNoValue") c = loadChart(t, "testdata/subpop") - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") cc = common.Values(c.Values) val, err := cc.PathValue("ensurenull") - if err != nil { - t.Error("expect value but ensurenull was not found") - } - if val != nil { - t.Errorf("expect nil value but got %q instead", val) - } + require.NoError(t, err, "expect value but ensurenull was not found") + assert.Nil(t, val, "expect nil value but got %q instead", val) } func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T) { c := loadChart(t, "testdata/chart-with-import-from-aliased-dependencies") - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") e := make(map[string]string) e["foo-defaults.defaultValue"] = "42" @@ -293,12 +258,8 @@ func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T cValues := common.Values(c.Values) for kk, vv := range e { pv, err := cValues.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } - if pv != vv { - t.Errorf("failed to match imported value %v with expected %v", pv, vv) - } + require.NoError(t, err, "retrieving import values table %v", kk) + assert.Equal(t, vv, pv, "failed to match imported value %v with expected %v", pv, vv) } } @@ -325,25 +286,18 @@ func TestProcessDependencyImportValuesMultiLevelPrecedence(t *testing.T) { e["app2.service.port"] = "8080" e["app3.service.port"] = "9090" e["app4.service.port"] = "1234" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v", s, vv) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, s, vv, "failed to match imported float value %v with expected %v", s, vv) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q", pv, vv) - } + assert.Equal(t, vv, pv, "failed to match imported string value %q with expected %q", pv, vv) } } } @@ -352,127 +306,71 @@ func TestProcessDependencyImportValuesForEnabledCharts(t *testing.T) { c := loadChart(t, "testdata/import-values-from-enabled-subchart/parent-chart") nameOverride := "parent-chart-prod" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 1 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } - + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 1, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) prodDependencyValues := c.Dependencies()[0].Values - if prodDependencyValues["nameOverride"] != nameOverride { - t.Fatalf("dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) - } + require.Equal(t, nameOverride, prodDependencyValues["nameOverride"], "dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) } func TestGetAliasDependency(t *testing.T) { c := loadChart(t, "testdata/frobnitz") req := c.Metadata.Dependencies - if len(req) == 0 { - t.Fatal("there are no dependencies to test") - } + require.NotEmpty(t, req, "there are no dependencies to test") // Success case aliasChart := getAliasDependency(c.Dependencies(), req[0]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[0].Name) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[0].Name) if req[0].Alias != "" { - if aliasChart.Name() != req[0].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[0].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) + require.Equal(t, req[0].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) + } else { + require.Equalf(t, aliasChart.Name(), req[0].Name, "dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) } if req[0].Version != "" { - if !IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version is not in the compatible range") - } + require.True(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version is not in the compatible range") } // Failure case req[0].Name = "something-else" - if aliasChart := getAliasDependency(c.Dependencies(), req[0]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nilf(t, getAliasDependency(c.Dependencies(), req[0]), "expected no chart") req[0].Version = "something else which is not in the compatible range" - if IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version outside the compatible range should fail, but it succeeded") - } + require.False(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version outside the compatible range should fail, but it succeeded") } func TestDependentChartAliases(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-alias") req := c.Metadata.Dependencies - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 3 { - t.Fatal("expected alias dependencies to be added") - } - - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 3, "expected alias dependencies to be added") + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) aliasChart := getAliasDependency(c.Dependencies(), req[2]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[2].Name) - } - if aliasChart.Parent() != c { - t.Fatalf("dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[2].Name) + require.Equal(t, c, aliasChart.Parent(), "dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) if req[2].Alias != "" { - if aliasChart.Name() != req[2].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[2].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) + require.Equal(t, req[2].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) + } else { + require.Equalf(t, aliasChart.Name(), req[2].Name, "dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) } req[2].Name = "dummy-name" - if aliasChart := getAliasDependency(c.Dependencies(), req[2]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nilf(t, getAliasDependency(c.Dependencies(), req[2]), "expected no chart") } func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-no-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") } func TestDependentChartWithSubChartsHelmignore(t *testing.T) { @@ -482,67 +380,37 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { func TestDependentChartsWithSubChartsSymlink(t *testing.T) { joonix := filepath.Join("testdata", "joonix") - if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz"))) defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) c := loadChart(t, joonix) - if c.Name() != "joonix" { - t.Fatalf("unexpected chart name: %s", c.Name()) - } - if n := len(c.Dependencies()); n != 1 { - t.Fatalf("expected 1 dependency for this chart, but got %d", n) - } + require.Equal(t, "joonix", c.Name(), "unexpected chart name: %s", c.Name()) + require.Lenf(t, c.Dependencies(), 1, "expected 1 dependency for this chart") } func TestDependentChartsWithSubchartsAllSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-all-in-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) } func TestDependentChartsWithSomeSubchartsSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-mixed-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) } func validateDependencyTree(t *testing.T, c *chart.Chart) { t.Helper() for _, dependency := range c.Dependencies() { if dependency.Parent() != c { - if dependency.Parent() != c { - t.Fatalf("dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) - } + require.Equal(t, c, dependency.Parent(), "dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) } // recurse entire tree validateDependencyTree(t, dependency) @@ -552,16 +420,9 @@ func validateDependencyTree(t *testing.T, c *chart.Chart) { func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *testing.T) { c := loadChart(t, "testdata/chart-with-dependency-aliased-twice") - if len(c.Dependencies()) != 1 { - t.Fatalf("expected one dependency for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } + require.Len(t, c.Dependencies(), 1, "expected one dependency for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected two dependencies after processing aliases") - if len(c.Dependencies()) != 2 { - t.Fatal("expected two dependencies after processing aliases") - } validateDependencyTree(t, c) } diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index c80544b5b..95e429a0b 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -250,5 +250,5 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { require.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) // Verify creation annotation after (or equals) time test began - assert.False(t, nowTime.Before(createdTimeAnnotation), "%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) + assert.GreaterOrEqual(t, nowTime, createdTimeAnnotation, "%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) } diff --git a/pkg/repo/v1/chartrepo_test.go b/pkg/repo/v1/chartrepo_test.go index 9c992474b..4be2ebf73 100644 --- a/pkg/repo/v1/chartrepo_test.go +++ b/pkg/repo/v1/chartrepo_test.go @@ -18,7 +18,6 @@ package repo import ( "bytes" - "errors" "net/http" "net/http/httptest" "os" @@ -29,6 +28,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" "helm.sh/helm/v4/pkg/cli" @@ -68,37 +69,25 @@ func TestIndexCustomSchemeDownload(t *testing.T) { Name: repoName, URL: repoURL, }, providers) - if err != nil { - t.Fatalf("Problem loading chart repository from %s: %v", repoURL, err) - } + require.NoErrorf(t, err, "Problem loading chart repository from %s", repoURL) repo.CachePath = t.TempDir() tempIndexFile, err := os.CreateTemp(t.TempDir(), "test-repo") - if err != nil { - t.Fatalf("Failed to create temp index file: %v", err) - } + require.NoErrorf(t, err, "Failed to create temp index file") defer os.Remove(tempIndexFile.Name()) idx, err := repo.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if len(myCustomGetter.repoUrls) != 1 { - t.Fatal("Custom Getter.Get should be called once") - } + require.Len(t, myCustomGetter.repoUrls, 1, "Custom Getter.Get should be called once") expectedRepoIndexURL := repoURL + "/index.yaml" - if myCustomGetter.repoUrls[0] != expectedRepoIndexURL { - t.Fatalf("Custom Getter.Get should be called with %s", expectedRepoIndexURL) - } + require.Equalf(t, expectedRepoIndexURL, myCustomGetter.repoUrls[0], "Custom Getter.Get should be called with %s", expectedRepoIndexURL) } func TestConcurrencyDownloadIndex(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() repo, err := NewChartRepository(&Entry{ @@ -106,16 +95,12 @@ func TestConcurrencyDownloadIndex(t *testing.T) { URL: srv.URL, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Fatalf("Problem loading chart repository from %s: %v", srv.URL, err) - } + require.NoErrorf(t, err, "Problem loading chart repository from %s", srv.URL) repo.CachePath = t.TempDir() // initial download index idx, err := repo.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) indexFName := filepath.Join(repo.CachePath, helmpath.CacheIndexFile(repo.Config.Name)) @@ -128,16 +113,12 @@ func TestConcurrencyDownloadIndex(t *testing.T) { for range 150 { wg.Go(func() { idx, err := repo.DownloadIndexFile() - if err != nil { - t.Errorf("Failed to download index file to %s: %v", idx, err) - } + assert.NoErrorf(t, err, "Failed to download index file to %s", idx) }) wg.Go(func() { _, err := LoadIndexFile(indexFName) - if err != nil { - t.Errorf("Failed to load index file: %v", err) - } + assert.NoErrorf(t, err, "Failed to load index file") }) } wg.Wait() @@ -175,9 +156,7 @@ func startLocalTLSServerForTests(handler http.Handler) (*httptest.Server, error) func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { srv, err := startLocalTLSServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() chartURL, err := FindChartInRepoURL( @@ -186,12 +165,8 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { getter.All(&cli.EnvSettings{}), WithInsecureSkipTLSVerify(true), ) - if err != nil { - t.Fatalf("%v", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.2.0.tgz", chartURL, "%s is not the valid URL", chartURL) // If the insecureSkipTLSVerify is false, it will return an error that contains "x509: certificate signed by unknown authority". _, err = FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{}), WithChartVersion("0.1.0")) @@ -203,33 +178,23 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { if !strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") && !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) } - } else if !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { - t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) + } else { + assert.ErrorContainsf(t, err, "x509: certificate signed by unknown authority", "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error") } } func TestFindChartInRepoURL(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() chartURL, err := FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{})) - if err != nil { - t.Fatalf("%v", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.2.0.tgz", chartURL, "%s is not the valid URL", chartURL) chartURL, err = FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{}), WithChartVersion("0.1.0")) - if err != nil { - t.Errorf("%s", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.1.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.1.0.tgz", chartURL, "%s is not the valid URL", chartURL) } func TestErrorFindChartInRepoURL(t *testing.T) { @@ -237,38 +202,26 @@ func TestErrorFindChartInRepoURL(t *testing.T) { RepositoryCache: t.TempDir(), }) - if _, err := FindChartInRepoURL("http://someserver/something", "nginx", g); err == nil { - t.Error("Expected error for bad chart URL, but did not get any errors") - } else if !strings.Contains(err.Error(), `looks like "http://someserver/something" is not a valid chart repository or cannot be reached`) { - t.Errorf("Expected error for bad chart URL, but got a different error (%v)", err) - } + _, err := FindChartInRepoURL("http://someserver/something", "nginx", g) + require.Error(t, err, "Expected error for bad chart URL, but did not get any errors") + require.ErrorContainsf(t, err, `looks like "http://someserver/something" is not a valid chart repository or cannot be reached`, "Expected error for bad chart URL, but got a different error") srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() - if _, err = FindChartInRepoURL(srv.URL, "nginx1", g); err == nil { - t.Error("Expected error for chart not found, but did not get any errors") - } else if err.Error() != `chart "nginx1" not found in `+srv.URL+` repository` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } - if !errors.Is(err, ChartNotFoundError{}) { - t.Error("error is not of correct error type structure") - } + _, err = FindChartInRepoURL(srv.URL, "nginx1", g) + require.Error(t, err, "Expected error for chart not found, but did not get any errors") + require.EqualError(t, err, `chart "nginx1" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") + require.ErrorIs(t, err, ChartNotFoundError{}, "error is not of correct error type structure") - if _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")); err == nil { - t.Error("Expected error for chart not found, but did not get any errors") - } else if err.Error() != `chart "nginx1" version "0.1.0" not found in `+srv.URL+` repository` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } + _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")) + require.Error(t, err, "Expected error for chart not found, but did not get any errors") + require.EqualError(t, err, `chart "nginx1" version "0.1.0" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") - if _, err = FindChartInRepoURL(srv.URL, "chartWithNoURL", g); err == nil { - t.Error("Expected error for no chart URLs available, but did not get any errors") - } else if err.Error() != `chart "chartWithNoURL" has no downloadable URLs` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } + _, err = FindChartInRepoURL(srv.URL, "chartWithNoURL", g) + require.Error(t, err, "Expected error for no chart URLs available, but did not get any errors") + assert.EqualError(t, err, `chart "chartWithNoURL" has no downloadable URLs`, "Expected error for chart not found, but got a different error") } func TestResolveReferenceURL(t *testing.T) { @@ -286,11 +239,7 @@ func TestResolveReferenceURL(t *testing.T) { {"http://localhost:8123/charts?with=queryparameter", "/nginx-0.2.0.tgz", "http://localhost:8123/nginx-0.2.0.tgz?with=queryparameter"}, } { chartURL, err := ResolveReferenceURL(tt.baseURL, tt.refURL) - if err != nil { - t.Errorf("unexpected error in ResolveReferenceURL(%q, %q): %s", tt.baseURL, tt.refURL, err) - } - if chartURL != tt.chartURL { - t.Errorf("expected ResolveReferenceURL(%q, %q) to equal %q, got %q", tt.baseURL, tt.refURL, tt.chartURL, chartURL) - } + require.NoErrorf(t, err, "unexpected error in ResolveReferenceURL(%q, %q)", tt.baseURL, tt.refURL) + assert.Equalf(t, chartURL, tt.chartURL, "expected ResolveReferenceURL(%q, %q) to equal %q, got %q", tt.baseURL, tt.refURL, tt.chartURL, chartURL) } } From d4ec8e9b87a002d48c2d7a8f3c145c9a324bfaef Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 097/161] chore(pkg): refactor: convert tests to testify assert/require part 1 refactor: convert tests to testify assert/require in pkg/engine Signed-off-by: Matthieu MOREL --- pkg/engine/engine_test.go | 395 +++++++++----------------------------- 1 file changed, 96 insertions(+), 299 deletions(-) diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index f666b63a6..ecc1eee3b 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -51,9 +51,7 @@ func TestSortTemplates(t *testing.T) { "/mychart/templates/charts/bar/templates/foo.tpl": {}, } got := sortTemplates(tpls) - if len(got) != len(tpls) { - t.Fatal("Sorted results are missing templates") - } + require.Len(t, got, len(tpls), "Sorted results are missing templates") expect := []string{ "/mychart/templates/charts/foo/charts/bar/templates/foo.tpl", @@ -65,12 +63,7 @@ func TestSortTemplates(t *testing.T) { "/mychart/templates/_foo.tpl", } for i, e := range expect { - if got[i] != e { - t.Fatalf("\n\tExp:\n%s\n\tGot:\n%s", - strings.Join(expect, "\n"), - strings.Join(got, "\n"), - ) - } + require.Equal(t, e, got[i], "\n\tExp:\n%s\n\tGot:\n%s", strings.Join(expect, "\n"), strings.Join(got, "\n")) } } @@ -78,17 +71,15 @@ func TestFuncMap(t *testing.T) { fns := funcMap() forbidden := []string{"env", "expandenv"} for _, f := range forbidden { - if _, ok := fns[f]; ok { - t.Errorf("Forbidden function %s exists in FuncMap.", f) - } + _, ok := fns[f] + assert.Falsef(t, ok, "Forbidden function %s exists in FuncMap.", f) } // Test for Engine-specific template functions. expect := []string{"include", "required", "tpl", "toYaml", "fromYaml", "toToml", "fromToml", "toJson", "fromJson", "lookup"} for _, f := range expect { - if _, ok := fns[f]; !ok { - t.Errorf("Expected add-on function %q", f) - } + _, ok := fns[f] + assert.Truef(t, ok, "Expected add-on function %q", f) } } @@ -120,13 +111,9 @@ func TestRender(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") out, err := Render(c, v) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") expect := map[string]string{ "moby/templates/test1": "Spouter Inn", @@ -137,9 +124,7 @@ func TestRender(t *testing.T) { } for name, data := range expect { - if out[name] != data { - t.Errorf("Expected %q, got %q", data, out[name]) - } + assert.Equal(t, data, out[name], "Expected %q, got %q", data, out[name]) } } @@ -173,14 +158,10 @@ func TestRenderRefsOrdering(t *testing.T) { for i := range 100 { out, err := Render(parentChart, common.Values{}) - if err != nil { - t.Fatalf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for name, data := range expect { - if out[name] != data { - t.Fatalf("Expected %q, got %q (iteration %d)", data, out[name], i+1) - } + require.Equal(t, data, out[name], "Expected %q, got %q (iteration %d)", data, out[name], i+1) } } } @@ -198,25 +179,12 @@ func TestRenderInternals(t *testing.T) { } out, err := new(Engine).render(t.Context(), tpls) - if err != nil { - t.Fatalf("Failed template rendering: %s", err) - } - - if len(out) != 3 { - t.Fatalf("Expected 3 templates, got %d", len(out)) - } - - if out["one"] != "Hello One" { - t.Errorf("Expected 'Hello One', got %q", out["one"]) - } - if out["two"] != "Goodbye TWO" { - t.Errorf("Expected 'Goodbye TWO'. got %q", out["two"]) - } - - if out["three"] != "Goodbye THREE" { - t.Errorf("Expected 'Goodbye THREE'. got %q", out["two"]) - } + require.NoError(t, err, "Failed template rendering") + require.Len(t, out, 3, "Expected 3 templates, got %d", len(out)) + assert.Equal(t, "Hello One", out["one"]) + assert.Equal(t, "Goodbye TWO", out["two"]) + assert.Equal(t, "Goodbye THREE", out["three"]) } func TestRenderWithDNS(t *testing.T) { @@ -236,22 +204,16 @@ func TestRenderWithDNS(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") var e Engine e.EnableDNS = true out, err := e.Render(c, v) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for _, val := range c.Templates { fp := path.Join("moby", val.Name) - if out[fp] == "" { - t.Errorf("Expected IP address, got %q", out[fp]) - } + assert.NotEmpty(t, out[fp], "Expected IP address, got %q", out[fp]) } } @@ -375,21 +337,15 @@ func TestRenderWithClientProvider(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") out, err := RenderWithClientProvider(c, v, provider) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for name, want := range cases { t.Run(name, func(t *testing.T) { key := path.Join("moby/templates", name) - if out[key] != want.output { - t.Errorf("Expected %q, got %q", want, out[key]) - } + assert.Equal(t, want.output, out[key], "Expected %q, got %q", want, out[key]) }) } } @@ -411,9 +367,7 @@ func TestRenderWithClientProvider_error(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") provider := &testClientProvider{ t: t, @@ -424,9 +378,7 @@ func TestRenderWithClientProvider_error(t *testing.T) { }, } _, err = RenderWithClientProvider(c, v, provider) - if err == nil || !strings.Contains(err.Error(), "kaboom") { - t.Errorf("Expected error from client provider when rendering, got %q", err) - } + assert.ErrorContainsf(t, err, "kaboom", "Expected error from client provider when rendering") } func TestParallelRenderInternals(t *testing.T) { @@ -444,12 +396,8 @@ func TestParallelRenderInternals(t *testing.T) { }, } out, err := e.render(t.Context(), tpls) - if err != nil { - t.Errorf("Failed to render %s: %s", tt, err) - } - if out["t"] != tt { - t.Errorf("Expected %q, got %q", tt, out["t"]) - } + assert.NoError(t, err, "Failed to render %s", tt) + assert.Equal(t, tt, out["t"], "Expected %q, got %q", tt, out["t"]) wg.Done() }(i) } @@ -463,13 +411,9 @@ func TestParseErrors(t *testing.T) { "undefined_function": {tpl: `{{foo}}`, vals: vals}, } _, err := new(Engine).render(t.Context(), tplsUndefinedFunction) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } + require.Error(t, err, "Expected failures while rendering") expected := `parse error at (undefined_function:1): function "foo" not defined` - if err.Error() != expected { - t.Errorf("Expected '%s', got %q", expected, err.Error()) - } + assert.EqualError(t, err, expected) } func TestExecErrors(t *testing.T) { @@ -526,12 +470,8 @@ linebreak`, for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { _, err := new(Engine).render(t.Context(), tt.tpls) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } - if err.Error() != tt.expected { - t.Errorf("Expected %q, got %q", tt.expected, err.Error()) - } + require.Error(t, err, "Expected failures while rendering") + assert.EqualError(t, err, tt.expected) }) } } @@ -544,25 +484,15 @@ func TestFailErrors(t *testing.T) { "failtpl": {tpl: failtpl, vals: vals}, } _, err := new(Engine).render(t.Context(), tplsFailed) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } + require.Error(t, err, "Expected failures while rendering") expected := `execution error at (failtpl:1:33): This is an error` - if err.Error() != expected { - t.Errorf("Expected '%s', got %q", expected, err.Error()) - } + require.EqualError(t, err, expected) var e Engine e.LintMode = true out, err := e.render(t.Context(), tplsFailed) - if err != nil { - t.Fatal(err) - } - - expectStr := "All your base are belong to us" - if gotStr := out["failtpl"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } + require.NoError(t, err) + assert.Equal(t, "All your base are belong to us", out["failtpl"]) } func TestAllTemplates(t *testing.T) { @@ -592,9 +522,7 @@ func TestAllTemplates(t *testing.T) { dep1.AddDependency(dep2) tpls := allTemplates(ch1, common.Values{}) - if len(tpls) != 5 { - t.Errorf("Expected 5 charts, got %d", len(tpls)) - } + assert.Len(t, tpls, 5, "Expected 5 charts, got %d", len(tpls)) } func TestChartValuesContainsIsRoot(t *testing.T) { @@ -614,17 +542,13 @@ func TestChartValuesContainsIsRoot(t *testing.T) { ch1.AddDependency(dep1) out, err := Render(ch1, common.Values{}) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") expects := map[string]string{ "parent/charts/child/templates/isroot": "false", "parent/templates/isroot": "true", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -646,18 +570,10 @@ func TestRenderDependency(t *testing.T) { }) out, err := Render(ch, map[string]any{}) - if err != nil { - t.Fatalf("failed to render chart: %s", err) - } - - if len(out) != 2 { - t.Errorf("Expected 2, got %d", len(out)) - } + require.NoError(t, err, "failed to render chart") - expect := "Hello World" - if out["outerchart/templates/outer"] != expect { - t.Errorf("Expected %q, got %q", expect, out["outer"]) - } + assert.Len(t, out, 2, "Expected 2, got %d", len(out)) + assert.Equal(t, "Hello World", out["outerchart/templates/outer"]) } func TestRenderNestedValues(t *testing.T) { @@ -719,9 +635,7 @@ func TestRenderNestedValues(t *testing.T) { } tmp, err := util.CoalesceValues(outer, injValues) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") inject := common.Values{ "Values": tmp, @@ -734,34 +648,22 @@ func TestRenderNestedValues(t *testing.T) { t.Logf("Calculated values: %v", inject) out, err := Render(outer, inject) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") fullouterpath := "top/" + outerpath - if out[fullouterpath] != "Gather ye rosebuds while ye may" { - t.Errorf("Unexpected outer: %q", out[fullouterpath]) - } + assert.Equal(t, "Gather ye rosebuds while ye may", out[fullouterpath], "Unexpected outer: %q", out[fullouterpath]) fullinnerpath := "top/charts/herrick/" + innerpath - if out[fullinnerpath] != "Old time is still a-flyin'" { - t.Errorf("Unexpected inner: %q", out[fullinnerpath]) - } + assert.Equal(t, "Old time is still a-flyin'", out[fullinnerpath], "Unexpected inner: %q", out[fullinnerpath]) fulldeepestpath := "top/charts/herrick/charts/deepest/" + deepestpath - if out[fulldeepestpath] != "And this same flower that smiles to-day" { - t.Errorf("Unexpected deepest: %q", out[fulldeepestpath]) - } + assert.Equal(t, "And this same flower that smiles to-day", out[fulldeepestpath], "Unexpected deepest: %q", out[fulldeepestpath]) fullcheckrelease := "top/charts/herrick/charts/deepest/" + checkrelease - if out[fullcheckrelease] != "Tomorrow will be dyin" { - t.Errorf("Unexpected release: %q", out[fullcheckrelease]) - } + assert.Equal(t, "Tomorrow will be dyin", out[fullcheckrelease], "Unexpected release: %q", out[fullcheckrelease]) fullchecksubcharts := "top/" + subchartspath - if out[fullchecksubcharts] != "The glorious Lamp of Heaven, the Sun" { - t.Errorf("Unexpected subcharts: %q", out[fullchecksubcharts]) - } + assert.Equal(t, "The glorious Lamp of Heaven, the Sun", out[fullchecksubcharts], "Unexpected subcharts: %q", out[fullchecksubcharts]) } func TestRenderBuiltinValues(t *testing.T) { @@ -798,9 +700,7 @@ func TestRenderBuiltinValues(t *testing.T) { t.Logf("Calculated values: %v", outer) out, err := Render(outer, inject) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") expects := map[string]string{ "Troy/charts/Latium/templates/Lavinia": "Troy/charts/Latium/templates/LaviniaLatiumAeneid", @@ -809,9 +709,7 @@ func TestRenderBuiltinValues(t *testing.T) { "Troy/charts/Latium/templates/From": "Virgil Aeneid", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -843,20 +741,12 @@ func TestAlterFuncMap_include(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := " Mistah Kurtz - he dead." - if got := out["conrad/templates/quote"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, " Mistah Kurtz - he dead.", out["conrad/templates/quote"]) _, err = Render(d, v) expectErrName := "nested/templates/quote" - if err == nil { - t.Errorf("Expected err of nested reference name: %v", expectErrName) - } + assert.Error(t, err, "Expected err of nested reference name: %v", expectErrName) } func TestAlterFuncMap_require(t *testing.T) { @@ -881,18 +771,10 @@ func TestAlterFuncMap_require(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - expectStr := "All your base are belong to us" - if gotStr := out["conan/templates/quote"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } - expectNum := "All 2 of them!" - if gotNum := out["conan/templates/bases"]; gotNum != expectNum { - t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) - } + assert.Equal(t, "All your base are belong to us", out["conan/templates/quote"]) + assert.Equal(t, "All 2 of them!", out["conan/templates/bases"]) // test required without passing in needed values with lint mode on // verifies lint replaces required with an empty string (should not fail) @@ -907,19 +789,11 @@ func TestAlterFuncMap_require(t *testing.T) { } var e Engine e.LintMode = true - out, err = e.Render(c, lintValues) - if err != nil { - t.Fatal(err) - } - expectStr = "All your base are belong to us" - if gotStr := out["conan/templates/quote"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } - expectNum = "All of them!" - if gotNum := out["conan/templates/bases"]; gotNum != expectNum { - t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) - } + out, err = e.Render(c, lintValues) + require.NoError(t, err) + assert.Equal(t, "All your base are belong to us", out["conan/templates/quote"]) + assert.Equal(t, "All of them!", out["conan/templates/bases"]) } func TestAlterFuncMap_tpl(t *testing.T) { @@ -941,14 +815,8 @@ func TestAlterFuncMap_tpl(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "Evaluate tpl Value: myvalue" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "Evaluate tpl Value: myvalue", out["TplFunction/templates/base"]) } func TestAlterFuncMap_tplfunc(t *testing.T) { @@ -970,14 +838,8 @@ func TestAlterFuncMap_tplfunc(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "Evaluate tpl Value: \"myvalue\"" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "Evaluate tpl Value: \"myvalue\"", out["TplFunction/templates/base"]) } func TestAlterFuncMap_tplinclude(t *testing.T) { @@ -1000,14 +862,8 @@ func TestAlterFuncMap_tplinclude(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "\"TplFunction/templates/base\"" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "\"TplFunction/templates/base\"", out["TplFunction/templates/base"]) } func TestRenderRecursionLimit(t *testing.T) { @@ -1053,9 +909,7 @@ func TestRenderRecursionLimit(t *testing.T) { } out, err := Render(d, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var expect string var expectSb1062 strings.Builder @@ -1063,9 +917,7 @@ func TestRenderRecursionLimit(t *testing.T) { expectSb1062.WriteString(phrase + "\n") } expect += expectSb1062.String() - if got := out["overlook/templates/quote"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + assert.Equal(t, expect, out["overlook/templates/quote"]) } func TestRenderLoadTemplateForTplFromFile(t *testing.T) { @@ -1094,14 +946,8 @@ func TestRenderLoadTemplateForTplFromFile(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "test-function nested-define-content" - if got := out["TplLoadFromFile/templates/base"]; got != expect { - t.Fatalf("Expected %q, got %q", expect, got) - } + require.NoError(t, err) + require.Equal(t, "test-function nested-define-content", out["TplLoadFromFile/templates/base"]) } func TestRenderTplEmpty(t *testing.T) { @@ -1122,9 +968,7 @@ func TestRenderTplEmpty(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplEmpty/templates/empty-string": "", @@ -1132,9 +976,7 @@ func TestRenderTplEmpty(t *testing.T) { "TplEmpty/templates/only-defines": "", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1168,9 +1010,7 @@ func TestRenderTplTemplateNames(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplTemplateNames/templates/default-basepath": "TplTemplateNames/templates", @@ -1180,9 +1020,7 @@ func TestRenderTplTemplateNames(t *testing.T) { "TplTemplateNames/templates/modified-field": "extra-field", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1232,9 +1070,7 @@ func TestRenderTplRedefines(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplRedefines/templates/partial": `before: original-in-partial\ntpl: redefined-in-tpl\nafter: original-in-partial`, @@ -1247,9 +1083,7 @@ func TestRenderTplRedefines(t *testing.T) { `after: original-in-manifest original-outer-in-manifest`, } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1272,17 +1106,13 @@ func TestRenderTplMissingKey(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplMissingKey/templates/manifest": `missingValue: `, } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1307,15 +1137,9 @@ func TestRenderTplMissingKeyString(t *testing.T) { e := new(Engine) e.Strict = true - out, err := e.Render(c, v) - if err == nil { - t.Errorf("Expected error, got %v", out) - return - } - errTxt := fmt.Sprint(err) - if !strings.Contains(errTxt, "noSuchKey") { - t.Errorf("Expected error to contain 'noSuchKey', got %s", errTxt) - } + _, err := e.Render(c, v) + require.Error(t, err) + assert.ErrorContains(t, err, "noSuchKey") } func TestNestedHelpersProducesMultilineStacktrace(t *testing.T) { @@ -1354,7 +1178,7 @@ NestedHelperFunctions/charts/common/templates/_helpers_2.tpl:1:49 _, err := Render(c, vals) require.Error(t, err) - assert.Equal(t, expectedErrorMessage, err.Error()) + assert.EqualError(t, err, expectedErrorMessage) } func TestMultilineNoTemplateAssociatedError(t *testing.T) { @@ -1374,11 +1198,6 @@ func TestMultilineNoTemplateAssociatedError(t *testing.T) { }, } - expectedErrorMessage := `multiline/templates/svc.yaml:1:9 - executing "multiline/templates/svc.yaml" at : - error calling include: -template: no template "nested_helper.name" associated with template "gotpl"` - v := common.Values{} val, _ := util.CoalesceValues(c, v) @@ -1388,7 +1207,10 @@ template: no template "nested_helper.name" associated with template "gotpl"` _, err := Render(c, vals) require.Error(t, err) - assert.Equal(t, expectedErrorMessage, err.Error()) + assert.EqualError(t, err, `multiline/templates/svc.yaml:1:9 + executing "multiline/templates/svc.yaml" at : + error calling include: +template: no template "nested_helper.name" associated with template "gotpl"`) } func TestRenderCustomTemplateFuncs(t *testing.T) { @@ -1436,9 +1258,7 @@ func TestRenderCustomTemplateFuncs(t *testing.T) { // Render the chart. out, err := e.Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Expected output should be "hello!!!". expected := "hello!!!" @@ -1461,12 +1281,8 @@ func TestTraceableError_SimpleForm(t *testing.T) { } for _, errString := range testStrings { trace, done := parseTemplateSimpleErrorString(errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.message != "error calling include" { - t.Errorf("Expected %q, got %q", errString, trace.message) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, "error calling include", trace.message, "Expected %q, got %q", errString, trace.message) } } func TestTraceableError_ExecutingForm(t *testing.T) { @@ -1478,12 +1294,8 @@ func TestTraceableError_ExecutingForm(t *testing.T) { errString := errTuple[0] expectedLocation := errTuple[1] trace, done := parseTemplateExecutingAtErrorType(errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.location != expectedLocation { - t.Errorf("Expected %q, got %q", expectedLocation, trace.location) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, expectedLocation, trace.location, "Expected %q, got %q", expectedLocation, trace.location) } } @@ -1493,12 +1305,8 @@ func TestTraceableError_NoTemplateForm(t *testing.T) { } for _, errString := range testStrings { trace, done := parseTemplateNoTemplateError(errString, errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.message != errString { - t.Errorf("Expected %q, got %q", errString, trace.message) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, errString, trace.message, "Expected %q, got %q", errString, trace.message) } } @@ -1535,9 +1343,7 @@ func TestRenderSubchartDefaultNilNoStringify(t *testing.T) { injValues := map[string]any{} tmp, err := util.CoalesceValues(parent, injValues) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") inject := common.Values{ "Values": tmp, @@ -1548,18 +1354,9 @@ func TestRenderSubchartDefaultNilNoStringify(t *testing.T) { } out, err := Render(parent, inject) - if err != nil { - t.Fatalf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") rendered := out["parent/charts/child/templates/test.yaml"] - - if strings.Contains(rendered, "%!s()") { - t.Errorf("Rendered output contains %%!s(), got: %q", rendered) - } - - expected := "subPath: fallback" - if rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + assert.NotContains(t, rendered, "%!s()", "Rendered output contains %%!s(), got: %q", rendered) + assert.Equal(t, "subPath: fallback", rendered) } From 0daa77fa9bffe2c8359bb079d3e978fe74a0b5a4 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 098/161] chore(pkg): refactor: convert tests to testify assert/require part 2 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/cmd/flags_test.go | 9 +- pkg/getter/httpgetter_test.go | 345 +++++++++------------------------- 2 files changed, 93 insertions(+), 261 deletions(-) diff --git a/pkg/cmd/flags_test.go b/pkg/cmd/flags_test.go index 614970252..09dc61638 100644 --- a/pkg/cmd/flags_test.go +++ b/pkg/cmd/flags_test.go @@ -110,14 +110,11 @@ func TestPostRendererFlagSetOnce(t *testing.T) { }, } // Set the plugin name once - err := str.Set("postrenderer-v1") - require.NoError(t, err) + require.NoError(t, str.Set("postrenderer-v1")) // Set the plugin name again to the same value is not ok - err = str.Set("postrenderer-v1") - require.Error(t, err) + require.Error(t, str.Set("postrenderer-v1")) // Set the plugin name again to a different value is not ok - err = str.Set("cat") - require.Error(t, err) + require.Error(t, str.Set("cat")) } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index d7ba770b3..bfde5efa8 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -28,6 +28,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/tlsutil" "helm.sh/helm/v4/internal/version" "helm.sh/helm/v4/pkg/cli" @@ -35,13 +38,10 @@ import ( func TestHTTPGetter(t *testing.T) { g, err := NewHTTPGetter(WithURL("http://example.com")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := g.(*HTTPGetter); !ok { - t.Fatal("Expected NewHTTPGetter to produce an *HTTPGetter") - } + _, ok := g.(*HTTPGetter) + require.True(t, ok, "Expected NewHTTPGetter to produce an *HTTPGetter") cd := "../../testdata" join := filepath.Join @@ -60,54 +60,20 @@ func TestHTTPGetter(t *testing.T) { WithTimeout(timeout), WithTransport(transport), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok := g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - - if hg.opts.username != "I" { - t.Errorf("Expected NewHTTPGetter to contain %q as the username, got %q", "I", hg.opts.username) - } - - if hg.opts.password != "Am" { - t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password) - } - - if hg.opts.passCredentialsAll != false { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) - } - - if hg.opts.userAgent != "Groot" { - t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) - } - - if hg.opts.certFile != pub { - t.Errorf("Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile) - } - - if hg.opts.keyFile != priv { - t.Errorf("Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile) - } - - if hg.opts.caFile != ca { - t.Errorf("Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile) - } - - if hg.opts.insecureSkipVerifyTLS != insecure { - t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS) - } - - if hg.opts.timeout != timeout { - t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) - } - - if hg.opts.transport != transport { - t.Errorf("Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.Equal(t, "I", hg.opts.username, "Expected NewHTTPGetter to contain %q as the username, got %q", "I", hg.opts.username) + assert.Equal(t, "Am", hg.opts.password, "Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password) + assert.False(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) + assert.Equal(t, "Groot", hg.opts.userAgent, "Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) + assert.Equal(t, pub, hg.opts.certFile, "Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile) + assert.Equal(t, priv, hg.opts.keyFile, "Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile) + assert.Equal(t, ca, hg.opts.caFile, "Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile) + assert.Equal(t, insecure, hg.opts.insecureSkipVerifyTLS, "Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS) + assert.Equal(t, timeout, hg.opts.timeout, "Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) + assert.Same(t, transport, hg.opts.transport, "Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport) // Test if setting insecureSkipVerifyTLS is being passed to the ops insecure = true @@ -115,65 +81,42 @@ func TestHTTPGetter(t *testing.T) { g, err = NewHTTPGetter( WithInsecureSkipVerifyTLS(insecure), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok = g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - - if hg.opts.insecureSkipVerifyTLS != insecure { - t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.Equal(t, insecure, hg.opts.insecureSkipVerifyTLS, "Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS) // Checking false by default - if hg.opts.passCredentialsAll != false { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) - } + assert.False(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) // Test setting PassCredentialsAll g, err = NewHTTPGetter( WithBasicAuth("I", "Am"), WithPassCredentialsAll(true), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok = g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - if hg.opts.passCredentialsAll != true { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.True(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll) } func TestDownload(t *testing.T) { expect := "Call me Ishmael" srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defaultUserAgent := version.GetUserAgent() - if r.UserAgent() != defaultUserAgent { - t.Errorf("Expected '%s', got '%s'", defaultUserAgent, r.UserAgent()) - } + assert.Equal(t, defaultUserAgent, r.UserAgent(), "Expected '%s', got '%s'", defaultUserAgent, r.UserAgent()) fmt.Fprint(w, expect) })) defer srv.Close() g, err := All(cli.New()).ByScheme("http") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err := g.Get(srv.URL, WithURL(srv.URL)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with http server const expectedUserAgent = "I am Groot" @@ -182,9 +125,7 @@ func TestDownload(t *testing.T) { if !ok || username != "username" || password != "password" { t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) } - if r.UserAgent() != expectedUserAgent { - t.Errorf("Expected '%s', got '%s'", expectedUserAgent, r.UserAgent()) - } + assert.Equal(t, expectedUserAgent, r.UserAgent(), "Expected '%s', got '%s'", expectedUserAgent, r.UserAgent()) fmt.Fprint(w, expect) })) @@ -197,17 +138,11 @@ func TestDownload(t *testing.T) { WithPassCredentialsAll(false), WithUserAgent(expectedUserAgent), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with Get URL differing from withURL crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -232,17 +167,11 @@ func TestDownload(t *testing.T) { WithBasicAuth("username", "password"), WithPassCredentialsAll(false), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with Get URL differing from withURL and should pass creds crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -267,24 +196,16 @@ func TestDownload(t *testing.T) { WithBasicAuth("username", "password"), WithPassCredentialsAll(true), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test server with varied Accept Header const expectedAcceptHeader = "application/gzip,application/octet-stream" acceptHeaderSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Accept") != expectedAcceptHeader { - t.Errorf("Expected '%s', got '%s'", expectedAcceptHeader, r.Header.Get("Accept")) - } + assert.Equal(t, expectedAcceptHeader, r.Header.Get("Accept"), "Expected '%s', got '%s'", expectedAcceptHeader, r.Header.Get("Accept")) fmt.Fprint(w, expect) })) @@ -294,13 +215,9 @@ func TestDownload(t *testing.T) { httpgetter, err = NewHTTPGetter( WithAcceptHeader(expectedAcceptHeader), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestDownloadTLS(t *testing.T) { @@ -314,9 +231,7 @@ func TestDownloadTLS(t *testing.T) { tlsutil.WithCertKeyPairFiles(pub, priv), tlsutil.WithCAFile(ca), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsConf.ServerName = "helm.sh" tlsSrv.TLS = tlsConf tlsSrv.StartTLS() @@ -327,33 +242,24 @@ func TestDownloadTLS(t *testing.T) { WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String()); err != nil { - t.Error(err) - } + _, err = g.Get(u.String()) + require.NoError(t, err) // now test with TLS config being passed along in .Get (see #6635) g, err = NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil { - t.Error(err) - } + _, err = g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)) + require.NoError(t, err) // test with only the CA file (see also #6635) g, err = NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)); err != nil { - t.Error(err) - } + _, err = g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)) + assert.NoError(t, err) } func TestDownloadTLSWithRedirect(t *testing.T) { @@ -369,9 +275,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) { tlsutil.WithInsecureSkipVerify(insecureSkipTLSVerify), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsSrv2 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Header().Set("Content-Type", "text/plain") @@ -390,9 +294,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) { tlsutil.WithInsecureSkipVerify(insecureSkipTLSVerify), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsSrv1 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { u, _ := url.ParseRequestURI(tlsSrv2.URL) @@ -419,65 +321,41 @@ func TestDownloadTLSWithRedirect(t *testing.T) { WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String()) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) t.Run("Test with TLS config being passed along in .Get (see #6635)", func(t *testing.T) { g, err := NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) t.Run("Test with only the CA file (see also #6635)", func(t *testing.T) { g, err := NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) } @@ -491,25 +369,19 @@ func TestDownloadInsecureSkipTLSVerify(t *testing.T) { g, err := NewHTTPGetter( WithURL(u.String()), ) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String()); err == nil { - t.Errorf("Expected Getter to throw an error, got %s", err) - } + _, err = g.Get(u.String()) + require.Errorf(t, err, "Expected Getter to throw an error") // Test certificate check skip g, err = NewHTTPGetter( WithURL(u.String()), WithInsecureSkipVerifyTLS(true), ) - if err != nil { - t.Error(err) - } - if _, err = g.Get(u.String()); err != nil { - t.Error(err) - } + require.NoError(t, err) + _, err = g.Get(u.String()) + assert.NoError(t, err) } func TestHTTPGetterTarDownload(t *testing.T) { @@ -535,17 +407,13 @@ func TestHTTPGetterTarDownload(t *testing.T) { defer srv.Close() g, err := NewHTTPGetter(WithURL(srv.URL)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) data, _ := g.Get(srv.URL) mimeType := http.DetectContentType(data.Bytes()) expectedMimeType := "application/x-gzip" - if mimeType != expectedMimeType { - t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) - } + require.Equal(t, expectedMimeType, mimeType, "Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) } func TestHttpClientInsecureSkipVerify(t *testing.T) { @@ -569,31 +437,22 @@ func TestHttpClientInsecureSkipVerify(t *testing.T) { g.opts.keyFile = "testdata/client.key" g.opts.insecureSkipVerifyTLS = true transport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", true) - if len(transport.TLSClientConfig.Certificates) == 0 { - t.Fatal("transport.TLSClientConfig.Certificates is not present") - } + require.NotEmpty(t, transport.TLSClientConfig.Certificates, "transport.TLSClientConfig.Certificates is not present") } func verifyInsecureSkipVerify(t *testing.T, g *HTTPGetter, caseName string, expectedValue bool) *http.Transport { t.Helper() returnVal, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if returnVal == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, returnVal, "Expected non nil value for http client") transport := (returnVal.Transport).(*http.Transport) gotValue := false if transport.TLSClientConfig != nil { gotValue = transport.TLSClientConfig.InsecureSkipVerify } - if gotValue != expectedValue { - t.Fatalf("Case Name = %s\nInsecureSkipVerify did not come as expected. Expected = %t; Got = %v", - caseName, expectedValue, gotValue) - } + require.Equal(t, expectedValue, gotValue, "Case Name = %s\nInsecureSkipVerify did not come as expected. Expected = %t; Got = %v", caseName, expectedValue, gotValue) return transport } @@ -602,31 +461,21 @@ func TestDefaultHTTPTransportReuse(t *testing.T) { httpClient1, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient1 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient1, "Expected non nil value for http client") transport1 := (httpClient1.Transport).(*http.Transport) httpClient2, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient2 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient2, "Expected non nil value for http client") transport2 := (httpClient2.Transport).(*http.Transport) - if transport1 != transport2 { - t.Fatal("Expected default transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected default transport to be reused") } func TestHTTPTransportOption(t *testing.T) { @@ -636,35 +485,23 @@ func TestHTTPTransportOption(t *testing.T) { g.opts.transport = transport httpClient1, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient1 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient1, "Expected non nil value for http client") transport1 := (httpClient1.Transport).(*http.Transport) - if transport1 != transport { - t.Fatal("Expected transport option to be applied") - } + require.Equal(t, transport, transport1, "Expected transport option to be applied") httpClient2, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient2 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient2, "Expected non nil value for http client") transport2 := (httpClient2.Transport).(*http.Transport) - if transport1 != transport2 { - t.Fatal("Expected applied transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected applied transport to be reused") g = HTTPGetter{} g.opts.url = "https://localhost" @@ -673,7 +510,5 @@ func TestHTTPTransportOption(t *testing.T) { g.opts.insecureSkipVerifyTLS = true g.opts.transport = transport usedTransport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", false) - if usedTransport.TLSClientConfig != nil { - t.Fatal("transport.TLSClientConfig should not be set") - } + require.Nil(t, usedTransport.TLSClientConfig, "transport.TLSClientConfig should not be set") } From ca1767b81397e5ee3b3a5f7926590ddf1134c9c5 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 099/161] chore(pkg): refactor: convert tests to testify assert/require part 7 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/chart/v2/util/save_test.go | 133 +++++------------- pkg/cmd/upgrade_test.go | 250 +++++++++------------------------ 2 files changed, 104 insertions(+), 279 deletions(-) diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index 55c67f49e..1795226bc 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -37,6 +37,7 @@ import ( chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -62,29 +63,16 @@ func TestSave(t *testing.T) { chartWithInvalidJSON := withSchema(*c, []byte("{")) where, err := Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } - if !strings.HasPrefix(where, dest) { - t.Fatalf("Expected %q to start with %q", where, dest) - } - if !strings.HasSuffix(where, ".tgz") { - t.Fatalf("Expected %q to end with .tgz", where) - } + require.NoError(t, err, "Failed to save") + require.Truef(t, strings.HasPrefix(where, dest), "Expected %q to start with %q", where, dest) + require.Truef(t, strings.HasSuffix(where, ".tgz"), "Expected %q to end with .tgz", where) c2, err := loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } - if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { - t.Fatal("Files data did not match") - } - if c2.Lock != nil { - t.Fatal("Expected v1 chart archive not to contain Chart.lock file") - } + require.NoError(t, err) + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, "scheherazade/shahryar.txt", c2.Files[0].Name, "Files data did not match") + require.Nil(t, c2.Lock, "Expected v1 chart archive not to contain Chart.lock file") if !bytes.Equal(c.Schema, c2.Schema) { indentation := 4 @@ -92,25 +80,16 @@ func TestSave(t *testing.T) { formattedActual := Indent(indentation, string(c2.Schema)) t.Fatalf("Schema data did not match.\nExpected:\n%s\nActual:\n%s", formattedExpected, formattedActual) } - if _, err := Save(&chartWithInvalidJSON, dest); err == nil { - t.Fatal("Invalid JSON was not caught while saving chart") - } + _, err = Save(&chartWithInvalidJSON, dest) + require.Error(t, err, "Invalid JSON was not caught while saving chart") c.Metadata.APIVersion = chart.APIVersionV2 where, err = Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") c2, err = loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Lock == nil { - t.Fatal("Expected v2 chart archive to contain a Chart.lock file") - } - if c2.Lock.Digest != c.Lock.Digest { - t.Fatal("Chart.lock data did not match") - } + require.NoError(t, err) + require.NotNil(t, c2.Lock, "Expected v2 chart archive to contain a Chart.lock file") + require.Equal(t, c.Lock.Digest, c2.Lock.Digest, "Chart.lock data did not match") }) } @@ -128,9 +107,7 @@ func TestSave(t *testing.T) { }, } _, err := Save(c, tmp) - if err == nil { - t.Fatal("Expected error saving chart with invalid name") - } + require.Error(t, err, "Expected error saving chart with invalid name") } // https://github.com/helm/helm/issues/31844 @@ -145,20 +122,14 @@ func TestSavedGzipExtraFieldIsValid(t *testing.T) { } where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") f, err := os.Open(where) - if err != nil { - t.Fatalf("Failed to open saved file: %s", err) - } + require.NoError(t, err, "Failed to open saved file") defer f.Close() r, err := gzip.NewReader(f) - if err != nil { - t.Fatalf("Failed to create gzip reader: %s", err) - } + require.NoError(t, err, "Failed to create gzip reader") defer r.Close() // RFC 1952 §2.3.1.1: @@ -214,20 +185,14 @@ func TestSavePreservesTimestamps(t *testing.T) { } where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - if err != nil { - t.Fatalf("Failed to parse tar: %v", err) - } + require.NoError(t, err, "Failed to parse tar") roundedTime := initialCreateTime.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(roundedTime) { - t.Fatalf("File timestamp not preserved: %v", header.ModTime) - } + require.Truef(t, header.ModTime.Equal(roundedTime), "File timestamp not preserved: %v", header.ModTime) } } @@ -248,20 +213,14 @@ func TestSaveWithSourceDateEpoch(t *testing.T) { c.StampModTimes(epoch) where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - if err != nil { - t.Fatalf("Failed to parse tar: %v", err) - } + require.NoError(t, err, "Failed to parse tar") expected := epoch.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(expected) { - t.Fatalf("Expected SOURCE_DATE_EPOCH timestamp %v, got %v for %q", expected, header.ModTime, header.Name) - } + require.Truef(t, header.ModTime.Equal(expected), "Expected SOURCE_DATE_EPOCH timestamp %v, got %v for %q", expected, header.ModTime, header.Name) } } @@ -317,37 +276,25 @@ func TestSaveDir(t *testing.T) { }, } - if err := SaveDir(c, tmp); err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoErrorf(t, SaveDir(c, tmp), "Failed to save") c2, err := loader.LoadDir(tmp + "/ahab") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - if len(c2.Templates) != 1 || c2.Templates[0].Name != c.Templates[0].Name { - t.Fatal("Templates data did not match") - } + require.Len(t, c2.Templates, 1, "Templates data did not match") + require.Equal(t, c2.Templates[0].Name, c.Templates[0].Name, "Templates data did not match") - if len(c2.Files) != 1 || c2.Files[0].Name != c.Files[0].Name { - t.Fatal("Files data did not match") - } + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, c2.Files[0].Name, c.Files[0].Name, "Files data did not match") tmp2 := t.TempDir() c.Metadata.Name = "../ahab" pth := filepath.Join(tmp2, "tmpcharts") - if err := os.MkdirAll(filepath.Join(pth), 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(pth), 0o755)) - if err := SaveDir(c, pth); err.Error() != "\"../ahab\" is not a valid chart name" { - t.Fatalf("Did not get expected error for chart named %q", c.Name()) - } + require.EqualErrorf(t, SaveDir(c, pth), "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) } func TestRepeatableSave(t *testing.T) { @@ -408,18 +355,12 @@ func TestRepeatableSave(t *testing.T) { // create package dest := path.Join(tmp, "newdir") where, err := Save(test.chart, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") // get shasum for package result, err := sha256Sum(where) - if err != nil { - t.Fatalf("Failed to check shasum: %s", err) - } + require.NoError(t, err, "Failed to check shasum") // assert that the package SHA is what we wanted. - if result != test.want { - t.Errorf("FormatName() result = %v, want %v", result, test.want) - } + assert.Equal(t, test.want, result, "FormatName() result = %v, want %v", result, test.want) }) } } diff --git a/pkg/cmd/upgrade_test.go b/pkg/cmd/upgrade_test.go index 30188d3d9..ab6c43235 100644 --- a/pkg/cmd/upgrade_test.go +++ b/pkg/cmd/upgrade_test.go @@ -21,10 +21,12 @@ import ( "os" "path/filepath" "reflect" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -44,13 +46,9 @@ func TestUpgradeCmd(t *testing.T) { }, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: "funny-bunny", Chart: ch, @@ -59,25 +57,17 @@ func TestUpgradeCmd(t *testing.T) { // update chart version cfile.Metadata.Version = "0.1.2" - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart") ch, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading updated chart: %v", err) - } + require.NoError(t, err, "Error loading updated chart") // update chart version again cfile.Metadata.Version = "0.1.3" - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart") var ch2 *chart.Chart ch2, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading updated chart: %v", err) - } + require.NoError(t, err, "Error loading updated chart") missingDepsPath := "testdata/testcharts/chart-missing-deps" badDepsPath := "testdata/testcharts/chart-bad-requirements" @@ -205,22 +195,14 @@ func TestUpgradeWithValue(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --set favoriteDrink=tea '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: tea") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: tea", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeWithStringValue(t *testing.T) { @@ -235,22 +217,14 @@ func TestUpgradeWithStringValue(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --set-string favoriteDrink=coffee '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: coffee") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: coffee", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeInstallWithSubchartNotes(t *testing.T) { @@ -265,26 +239,15 @@ func TestUpgradeInstallWithSubchartNotes(t *testing.T) { cmd := fmt.Sprintf("upgrade %s -i --render-subchart-notes '%s'", releaseName, "testdata/testcharts/chart-with-subchart-notes") _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) upgradedReli, err := store.Get(releaseName, 2) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - upgradedRel, err := releaserToV1Release(upgradedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(upgradedRel.Info.Notes, "PARENT NOTES") { - t.Errorf("The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) - } - - if !strings.Contains(upgradedRel.Info.Notes, "SUBCHART NOTES") { - t.Errorf("The subchart notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) - } + upgradedRel, err := releaserToV1Release(upgradedReli) + require.NoError(t, err) + assert.Contains(t, upgradedRel.Info.Notes, "PARENT NOTES", "The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) + assert.Contains(t, upgradedRel.Info.Notes, "SUBCHART NOTES", "The subchart notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) } func TestUpgradeWithValuesFile(t *testing.T) { @@ -299,22 +262,14 @@ func TestUpgradeWithValuesFile(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --values testdata/testcharts/upgradetest/values.yaml '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeWithValuesFromStdin(t *testing.T) { @@ -328,28 +283,18 @@ func TestUpgradeWithValuesFromStdin(t *testing.T) { store.Create(relMock(releaseName, 3, ch)) in, err := os.Open("testdata/testcharts/upgradetest/values.yaml") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd := fmt.Sprintf("upgrade %s --values - '%s'", releaseName, chartPath) _, _, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeInstallWithValuesFromStdin(t *testing.T) { @@ -361,37 +306,25 @@ func TestUpgradeInstallWithValuesFromStdin(t *testing.T) { store := storageFixture() in, err := os.Open("testdata/testcharts/upgradetest/values.yaml") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd := fmt.Sprintf("upgrade %s -f - --install '%s'", releaseName, chartPath) _, _, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func prepareMockRelease(t *testing.T, releaseName string) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { t.Helper() tmpChart := t.TempDir() configmapData, err := os.ReadFile("testdata/testcharts/upgradetest/templates/configmap.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") cfile := &chart.Chart{ Metadata: &chart.Metadata{ APIVersion: chart.APIVersionV1, @@ -402,13 +335,9 @@ func prepareMockRelease(t *testing.T, releaseName string) (func(n string, v int, Templates: []*common.File{{Name: "templates/configmap.yaml", ModTime: time.Now(), Data: configmapData}}, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: releaseName, Chart: ch, @@ -475,35 +404,23 @@ func TestUpgradeInstallWithLabels(t *testing.T) { } cmd := fmt.Sprintf("upgrade %s --install --labels key1=val1,key2=val2 '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !reflect.DeepEqual(updatedRel.Labels, expectedLabels) { - t.Errorf("Expected {%v}, got {%v}", expectedLabels, updatedRel.Labels) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Truef(t, reflect.DeepEqual(updatedRel.Labels, expectedLabels), "Expected {%v}, got {%v}", expectedLabels, updatedRel.Labels) } func prepareMockReleaseWithSecret(t *testing.T, releaseName string) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { t.Helper() tmpChart := t.TempDir() configmapData, err := os.ReadFile("testdata/testcharts/chart-with-secret/templates/configmap.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") secretData, err := os.ReadFile("testdata/testcharts/chart-with-secret/templates/secret.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") modTime := time.Now() cfile := &chart.Chart{ Metadata: &chart.Metadata{ @@ -515,13 +432,9 @@ func prepareMockReleaseWithSecret(t *testing.T, releaseName string) (func(n stri Templates: []*common.File{{Name: "templates/configmap.yaml", ModTime: modTime, Data: configmapData}, {Name: "templates/secret.yaml", ModTime: modTime, Data: secretData}}, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: releaseName, Chart: ch, @@ -546,54 +459,34 @@ func TestUpgradeWithDryRun(t *testing.T) { // have it available. cmd := fmt.Sprintf("upgrade %s --install '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) _, err = store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd = fmt.Sprintf("upgrade %s --dry-run '%s'", releaseName, chartPath) _, out, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) // No second release should be stored because this is a dry run. _, err = store.Get(releaseName, 2) - if err == nil { - t.Error("expected error as there should be no new release but got none") - } - - if !strings.Contains(out, "kind: Secret") { - t.Error("expected secret in output from --dry-run but found none") - } + require.Error(t, err, "expected error as there should be no new release but got none") + assert.Contains(t, out, "kind: Secret", "expected secret in output from --dry-run but found none") // Ensure the secret is not in the output cmd = fmt.Sprintf("upgrade %s --dry-run --hide-secret '%s'", releaseName, chartPath) _, out, err = executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) // No second release should be stored because this is a dry run. _, err = store.Get(releaseName, 2) - if err == nil { - t.Error("expected error as there should be no new release but got none") - } - - if strings.Contains(out, "kind: Secret") { - t.Error("expected no secret in output from --dry-run --hide-secret but found one") - } + require.Error(t, err, "expected error as there should be no new release but got none") + assert.NotContains(t, out, "kind: Secret", "expected no secret in output from --dry-run --hide-secret but found one") // Ensure there is an error when --hide-secret used without dry-run cmd = fmt.Sprintf("upgrade %s --hide-secret '%s'", releaseName, chartPath) _, _, err = executeActionCommandC(store, cmd) - if err == nil { - t.Error("expected error when --hide-secret used without --dry-run") - } + assert.Error(t, err, "expected error when --hide-secret used without --dry-run") } func TestUpgradeInstallServerSideApply(t *testing.T) { @@ -630,23 +523,14 @@ func TestUpgradeInstallServerSideApply(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --install %s '%s'", releaseName, tt.serverSideFlag, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + require.NoError(t, err) rel, err := store.Get(releaseName, 1) - if err != nil { - t.Fatalf("unexpected error getting release: %v", err) - } + require.NoError(t, err, "unexpected error getting release") relV1, err := releaserToV1Release(rel) - if err != nil { - t.Fatalf("unexpected error converting release: %v", err) - } - - if relV1.ApplyMethod != tt.expectedApplyMethod { - t.Errorf("expected ApplyMethod %q, got %q", tt.expectedApplyMethod, relV1.ApplyMethod) - } + require.NoError(t, err, "unexpected error converting release") + assert.Equal(t, tt.expectedApplyMethod, relV1.ApplyMethod, "expected ApplyMethod %q, got %q", tt.expectedApplyMethod, relV1.ApplyMethod) }) } } From e5f0e07b96580305c3902eceb738cef230b44bec Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 100/161] chore(pkg): refactor: convert tests to testify assert/require part 8 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/chart/v2/chart_test.go | 10 +- pkg/kube/statuswait_test.go | 168 +++++++++++------------------ pkg/storage/driver/cfgmaps_test.go | 115 ++++++-------------- 3 files changed, 98 insertions(+), 195 deletions(-) diff --git a/pkg/chart/v2/chart_test.go b/pkg/chart/v2/chart_test.go index 813669366..313d65480 100644 --- a/pkg/chart/v2/chart_test.go +++ b/pkg/chart/v2/chart_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" ) @@ -76,15 +77,12 @@ func TestSaveChartNoRawData(t *testing.T) { } is := assert.New(t) + req := require.New(t) data, err := json.Marshal(chrt) - if err != nil { - t.Fatal(err) - } + req.NoError(err) res := &Chart{} - if err := json.Unmarshal(data, res); err != nil { - t.Fatal(err) - } + req.NoError(json.Unmarshal(data, res)) is.Equal([]*common.File(nil), res.Raw) } diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 21580b57a..5f5f5d051 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -272,8 +272,7 @@ func getRuntimeObjFromManifests(t *testing.T, manifests []string) []runtime.Obje objects := []runtime.Object{} for _, manifest := range manifests { m := make(map[string]any) - err := yaml.Unmarshal([]byte(manifest), &m) - require.NoError(t, err) + require.NoError(t, yaml.Unmarshal([]byte(manifest), &m)) resource := &unstructured.Unstructured{Object: m} objects = append(objects, resource) } @@ -332,8 +331,7 @@ func TestStatusWaitForDelete(t *testing.T) { for _, objToCreate := range objsToCreate { u := objToCreate.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } objsToDelete := getRuntimeObjFromManifests(t, tt.manifestsToDelete) for _, objToDelete := range objsToDelete { @@ -341,8 +339,7 @@ func TestStatusWaitForDelete(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilPodDelete) - err := fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } resourceList := getResourceListFromRuntimeObjs(t, c, objsToCreate) @@ -352,9 +349,9 @@ func TestStatusWaitForDelete(t *testing.T) { for _, expectedErrStr := range tt.expectErrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -375,8 +372,7 @@ func TestStatusWaitForDeleteNonExistentObject(t *testing.T) { // Don't create the object to test that the wait for delete works when the object doesn't exist objManifest := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) resourceList := getResourceListFromRuntimeObjs(t, c, objManifest) - err := statusWaiter.WaitForDelete(resourceList, timeout) - assert.NoError(t, err) + assert.NoError(t, statusWaiter.WaitForDelete(resourceList, timeout)) } func TestStatusWait(t *testing.T) { @@ -433,8 +429,7 @@ func TestStatusWait(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -443,9 +438,9 @@ func TestStatusWait(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -490,8 +485,7 @@ func TestWaitForJobComplete(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) @@ -500,9 +494,9 @@ func TestWaitForJobComplete(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -553,8 +547,7 @@ func TestWatchForReady(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) @@ -563,9 +556,9 @@ func TestWatchForReady(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -657,8 +650,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delete") { @@ -668,8 +660,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -681,9 +672,9 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -839,8 +830,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delet") { @@ -850,8 +840,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -863,10 +852,10 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { for _, expectedErr := range tt.expectErrs { require.ErrorContains(t, err, expectedErr.Error()) } - return + } else { + require.NoError(t, err) + assert.False(t, restrictedConfig.clusterScopedListAttempted) } - require.NoError(t, err) - assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } } @@ -947,8 +936,7 @@ func TestStatusWaitMixedResources(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delet") { @@ -958,8 +946,7 @@ func TestStatusWaitMixedResources(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -971,10 +958,10 @@ func TestStatusWaitMixedResources(t *testing.T) { for _, expectedErr := range tt.expectErrs { require.ErrorContains(t, err, expectedErr.Error()) } - return + } else { + require.NoError(t, err) + assert.False(t, restrictedConfig.clusterScopedListAttempted) } - require.NoError(t, err) - assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } } @@ -1067,8 +1054,7 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -1077,9 +1063,9 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1139,16 +1125,15 @@ func TestStatusWaitWithJobsAndCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) if tt.expectErrs != nil { assert.EqualError(t, err, errors.Join(tt.expectErrs...).Error()) - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1238,8 +1223,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := tt.testFunc(&sw, resourceList, time.Second*3) @@ -1248,9 +1232,9 @@ func TestStatusWaitWithFailedResources(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1343,14 +1327,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WatchUntilReady(resourceList, time.Second*3), "context canceled") }) t.Run("Wait uses method-specific context", func(t *testing.T) { @@ -1376,14 +1358,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.Wait(resourceList, time.Second*3), "context canceled") }) t.Run("WaitWithJobs uses method-specific context", func(t *testing.T) { @@ -1409,14 +1389,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitWithJobs(resourceList, time.Second*3), "context canceled") }) t.Run("WaitForDelete uses method-specific context", func(t *testing.T) { @@ -1442,14 +1420,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitForDelete(resourceList, time.Second*3), "context canceled") }) } @@ -1479,14 +1455,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WatchUntilReady(resourceList, time.Second*3), "context canceled") }) t.Run("Wait falls back to general context when method context is nil", func(t *testing.T) { @@ -1512,14 +1486,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.Wait(resourceList, time.Second*3), "context canceled") }) t.Run("WaitWithJobs falls back to general context when method context is nil", func(t *testing.T) { @@ -1545,14 +1517,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitWithJobs(resourceList, time.Second*3), "context canceled") }) t.Run("WaitForDelete falls back to general context when method context is nil", func(t *testing.T) { @@ -1578,14 +1548,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitForDelete(resourceList, time.Second*3), "context canceled") }) } @@ -1615,14 +1583,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WatchUntilReady(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for Wait", func(t *testing.T) { @@ -1648,14 +1614,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.Wait(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for WaitWithJobs", func(t *testing.T) { @@ -1681,14 +1645,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WaitWithJobs(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for WaitForDelete", func(t *testing.T) { @@ -1717,9 +1679,8 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { // immediately cancelled and the call would return a context error. objs := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WaitForDelete(resourceList, time.Second)) }) } @@ -1801,8 +1762,7 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) @@ -1811,9 +1771,9 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } diff --git a/pkg/storage/driver/cfgmaps_test.go b/pkg/storage/driver/cfgmaps_test.go index 947ebff71..e36aecce8 100644 --- a/pkg/storage/driver/cfgmaps_test.go +++ b/pkg/storage/driver/cfgmaps_test.go @@ -16,10 +16,11 @@ package driver import ( "encoding/base64" "encoding/json" - "errors" "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "helm.sh/helm/v4/pkg/release" @@ -29,9 +30,7 @@ import ( func TestConfigMapName(t *testing.T) { c := newTestFixtureCfgMaps(t) - if c.Name() != ConfigMapsDriverName { - t.Errorf("Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) - } + assert.Equal(t, ConfigMapsDriverName, c.Name(), "Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) } func TestConfigMapGet(t *testing.T) { @@ -45,13 +44,9 @@ func TestConfigMapGet(t *testing.T) { // get release with key got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func TestUncompressedConfigMapGet(t *testing.T) { @@ -63,13 +58,9 @@ func TestUncompressedConfigMapGet(t *testing.T) { // Create a test fixture which contains an uncompressed release cfgmap, err := newConfigMapsObject(key, rel, nil) - if err != nil { - t.Fatalf("Failed to create configmap: %s", err) - } + require.NoError(t, err, "Failed to create configmap") b, err := json.Marshal(rel) - if err != nil { - t.Fatalf("Failed to marshal release: %s", err) - } + require.NoError(t, err, "Failed to marshal release") cfgmap.Data["release"] = base64.StdEncoding.EncodeToString(b) var mock MockConfigMapsInterface mock.objects = map[string]*v1.ConfigMap{key: cfgmap} @@ -77,13 +68,9 @@ func TestUncompressedConfigMapGet(t *testing.T) { // get release with key got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func convertReleaserToV1(t *testing.T, rel release.Releaser) *rspb.Release { @@ -117,12 +104,8 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %s", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) // list all deployed releases dpl, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -130,12 +113,8 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) // list all superseded releases ssd, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -143,22 +122,14 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %s", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded") + assert.Len(t, ssd, 2, "Expected 2 superseded, got %d", len(ssd)) // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) } func TestConfigMapQuery(t *testing.T) { @@ -172,17 +143,11 @@ func TestConfigMapQuery(t *testing.T) { }...) rls, err := cfgmaps.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Failed to query: %s", err) - } - if len(rls) != 2 { - t.Errorf("Expected 2 results, got %d", len(rls)) - } + require.NoError(t, err, "Failed to query") + assert.Len(t, rls, 2, "Expected 2 results, got %d", len(rls)) _, err = cfgmaps.Query(map[string]string{"name": "notExist"}) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } func TestConfigMapCreate(t *testing.T) { @@ -195,20 +160,14 @@ func TestConfigMapCreate(t *testing.T) { rel := releaseStub(name, vers, namespace, common.StatusDeployed) // store the release in a configmap - if err := cfgmaps.Create(key, rel); err != nil { - t.Fatalf("Failed to create release with key %q: %s", key, err) - } + require.NoErrorf(t, cfgmaps.Create(key, rel), "Failed to create release with key %q", key) // get the release back got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func TestConfigMapUpdate(t *testing.T) { @@ -224,21 +183,15 @@ func TestConfigMapUpdate(t *testing.T) { rel.Info.Status = common.StatusSuperseded // perform the update - if err := cfgmaps.Update(key, rel); err != nil { - t.Fatalf("Failed to update release: %s", err) - } + require.NoErrorf(t, cfgmaps.Update(key, rel), "Failed to update release") // fetch the updated release goti, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) got := convertReleaserToV1(t, goti) // check release has actually been updated by comparing modified fields - if rel.Info.Status != got.Info.Status { - t.Errorf("Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) - } + assert.Equal(t, got.Info.Status, rel.Info.Status, "Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) } func TestConfigMapDelete(t *testing.T) { @@ -252,20 +205,12 @@ func TestConfigMapDelete(t *testing.T) { // perform the delete on a non-existent release _, err := cfgmaps.Delete("nonexistent") - if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("Expected ErrReleaseNotFound: got {%v}", err) - } + require.ErrorIs(t, err, ErrReleaseNotFound) // perform the delete rls, err := cfgmaps.Delete(key) - if err != nil { - t.Fatalf("Failed to delete release with key %q: %s", key, err) - } - if !reflect.DeepEqual(rel, rls) { - t.Errorf("Expected {%v}, got {%v}", rel, rls) - } + require.NoError(t, err, "Failed to delete release with key %q", key) + assert.Truef(t, reflect.DeepEqual(rel, rls), "Expected {%v}, got {%v}", rel, rls) _, err = cfgmaps.Get(key) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } From 13d1edc5f346e136b249d4c8232e83689f07c3b4 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 101/161] chore(pkg): refactor: convert tests to testify assert/require part 9 refactor: convert tests to testify assert/require in pkg/chart/common/util Signed-off-by: Matthieu MOREL --- pkg/chart/common/util/coalesce_test.go | 269 +++++++---------------- pkg/chart/common/util/jsonschema_test.go | 132 +++-------- pkg/cmd/completion_test.go | 6 +- 3 files changed, 116 insertions(+), 291 deletions(-) diff --git a/pkg/chart/common/util/coalesce_test.go b/pkg/chart/common/util/coalesce_test.go index d7f46a1da..6ef092365 100644 --- a/pkg/chart/common/util/coalesce_test.go +++ b/pkg/chart/common/util/coalesce_test.go @@ -141,9 +141,7 @@ func TestCoalesceValues(t *testing.T) { ) vals, err := common.ReadValues(testCoalesceValuesYaml) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // taking a copy of the values before passing it // to CoalesceValues as argument, so that we can @@ -152,9 +150,7 @@ func TestCoalesceValues(t *testing.T) { maps.Copy(valsCopy, vals) v, err := CoalesceValues(c, vals) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) j, _ := json.MarshalIndent(v, "", " ") t.Logf("Coalesced Values: %s", string(j)) @@ -211,32 +207,26 @@ func TestCoalesceValues(t *testing.T) { nullKeys := []string{"bottom", "right", "left", "front"} for _, nullKey := range nullKeys { - if _, ok := v[nullKey]; ok { - t.Errorf("Expected key %q to be removed, still present", nullKey) - } + _, ok := v[nullKey] + assert.Falsef(t, ok, "Expected key %q to be removed, still present", nullKey) } - if _, ok := v["nested"].(map[string]any)["boat"]; ok { - t.Error("Expected nested boat key to be removed, still present") - } + _, ok := v["nested"].(map[string]any)["boat"] + assert.False(t, ok, "Expected nested boat key to be removed, still present") subchart := v["pequod"].(map[string]any) - if _, ok := subchart["boat"]; ok { - t.Error("Expected subchart boat key to be removed, still present") - } + _, ok = subchart["boat"] + assert.False(t, ok, "Expected subchart boat key to be removed, still present") subsubchart := subchart["ahab"].(map[string]any) - if _, ok := subsubchart["boat"]; ok { - t.Error("Expected sub-subchart ahab boat key to be removed, still present") - } + _, ok = subsubchart["boat"] + assert.False(t, ok, "Expected sub-subchart ahab boat key to be removed, still present") - if _, ok := subsubchart["nested"].(map[string]any)["boat"]; ok { - t.Error("Expected sub-subchart nested boat key to be removed, still present") - } + _, ok = subsubchart["nested"].(map[string]any)["boat"] + assert.False(t, ok, "Expected sub-subchart nested boat key to be removed, still present") - if _, ok := subsubchart["object"]; ok { - t.Error("Expected sub-subchart object map to be removed, still present") - } + _, ok = subsubchart["object"] + assert.False(t, ok, "Expected sub-subchart object map to be removed, still present") // CoalesceValues should not mutate the passed arguments is.Equal(valsCopy, vals) @@ -306,9 +296,7 @@ func TestMergeValues(t *testing.T) { ) vals, err := common.ReadValues(testCoalesceValuesYaml) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // taking a copy of the values before passing it // to MergeValues as argument, so that we can @@ -317,9 +305,7 @@ func TestMergeValues(t *testing.T) { maps.Copy(valsCopy, vals) v, err := MergeValues(c, vals) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) j, _ := json.MarshalIndent(v, "", " ") t.Logf("Coalesced Values: %s", string(j)) @@ -377,25 +363,20 @@ func TestMergeValues(t *testing.T) { // removed. nullKeys := []string{"bottom", "right", "left", "front"} for _, nullKey := range nullKeys { - if vv, ok := v[nullKey]; !ok { - t.Errorf("Expected key %q to be present but it was removed", nullKey) - } else if vv != nil { - t.Errorf("Expected key %q to be null but it has a value of %v", nullKey, vv) - } + vv, ok := v[nullKey] + assert.Truef(t, ok, "Expected key %q to be present but it was removed", nullKey) + assert.Nilf(t, vv, "Expected key %q to be null but it has a value of %v", nullKey, vv) } - if _, ok := v["nested"].(map[string]any)["boat"]; !ok { - t.Error("Expected nested boat key to be present but it was removed") - } + _, ok := v["nested"].(map[string]any)["boat"] + assert.True(t, ok, "Expected nested boat key to be present but it was removed") subchart := v["pequod"].(map[string]any)["ahab"].(map[string]any) - if _, ok := subchart["boat"]; !ok { - t.Error("Expected subchart boat key to be present but it was removed") - } + _, ok = subchart["boat"] + assert.True(t, ok, "Expected subchart boat key to be present but it was removed") - if _, ok := subchart["nested"].(map[string]any)["bar"]; !ok { - t.Error("Expected subchart nested bar key to be present but it was removed") - } + _, ok = subchart["nested"].(map[string]any)["bar"] + assert.True(t, ok, "Expected subchart nested bar key to be present but it was removed") // CoalesceValues should not mutate the passed arguments is.Equal(valsCopy, vals) @@ -433,47 +414,27 @@ func TestCoalesceTables(t *testing.T) { // otherwise the values are coalesced. CoalesceTables(dst, src) - if dst["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst["name"]) - } - if dst["occupation"] != "whaler" { - t.Errorf("Unexpected occupation: %s", dst["occupation"]) - } + assert.Equal(t, "Ishmael", dst["name"], "Unexpected name: %s", dst["name"]) + assert.Equal(t, "whaler", dst["occupation"], "Unexpected occupation: %s", dst["occupation"]) addr, ok := dst["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr["street"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr["street"].(string), "Unexpected address: %v", addr["street"]) + assert.Equal(t, "Nantucket", addr["city"].(string), "Unexpected city: %v", addr["city"]) + assert.Equal(t, "MA", addr["state"].(string), "Unexpected state: %v", addr["state"]) - if addr["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr["city"]) - } + _, ok = addr["country"] + assert.False(t, ok, "The country is not left out.") - if addr["state"].(string) != "MA" { - t.Errorf("Unexpected state: %v", addr["state"]) - } + det, ok := dst["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst["details"]) - if _, ok = addr["country"]; ok { - t.Error("The country is not left out.") - } + _, ok = det["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst["boat"].(string), "Expected boat string, got %v", dst["boat"]) - if det, ok := dst["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst["details"]) - } else if _, ok := det["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst["boat"]) - } - - if _, ok = dst["hole"]; ok { - t.Error("The hole still exists.") - } + _, ok = dst["hole"] + assert.False(t, ok, "The hole still exists.") dst2 := map[string]any{ "name": "Ishmael", @@ -493,40 +454,21 @@ func TestCoalesceTables(t *testing.T) { // this happens when the --reuse-values flag is set but the chart has no modifications yet CoalesceTables(dst2, nil) - if dst2["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst2["name"]) - } + assert.Equal(t, "Ishmael", dst2["name"], "Unexpected name: %s", dst2["name"]) addr2, ok := dst2["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr2["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr2["street"]) - } - - if addr2["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr2["city"]) - } - - if addr2["country"].(string) != "US" { - t.Errorf("Unexpected Country: %v", addr2["country"]) - } - - if det2, ok := dst2["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst2["details"]) - } else if _, ok := det2["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst2["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst2["boat"]) - } - - if dst2["hole"].(string) != "black" { - t.Errorf("Expected hole string, got %v", dst2["boat"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr2["street"].(string), "Unexpected address: %v", addr2["street"]) + assert.Equal(t, "Nantucket", addr2["city"].(string), "Unexpected city: %v", addr2["city"]) + assert.Equal(t, "US", addr2["country"].(string), "Unexpected Country: %v", addr2["country"]) + + det2, ok := dst2["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst2["details"]) + + _, ok = det2["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst2["boat"].(string), "Expected boat string, got %v", dst2["boat"]) + assert.Equal(t, "black", dst2["hole"].(string), "Expected hole string, got %v", dst2["boat"]) } func TestMergeTables(t *testing.T) { @@ -561,51 +503,31 @@ func TestMergeTables(t *testing.T) { // otherwise the values are coalesced. MergeTables(dst, src) - if dst["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst["name"]) - } - if dst["occupation"] != "whaler" { - t.Errorf("Unexpected occupation: %s", dst["occupation"]) - } + assert.Equal(t, "Ishmael", dst["name"], "Unexpected name: %s", dst["name"]) + assert.Equal(t, "whaler", dst["occupation"], "Unexpected occupation: %s", dst["occupation"]) addr, ok := dst["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr["street"]) - } - - if addr["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr["city"]) - } - - if addr["state"].(string) != "MA" { - t.Errorf("Unexpected state: %v", addr["state"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr["street"].(string), "Unexpected address: %v", addr["street"]) + assert.Equal(t, "Nantucket", addr["city"].(string), "Unexpected city: %v", addr["city"]) + assert.Equal(t, "MA", addr["state"].(string), "Unexpected state: %v", addr["state"]) // This is one test that is different from CoalesceTables. Because country // is a nil value and it's not removed it's still present. - if _, ok = addr["country"]; !ok { - t.Error("The country is left out.") - } + _, ok = addr["country"] + assert.True(t, ok, "The country is left out.") - if det, ok := dst["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst["details"]) - } else if _, ok := det["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } + det, ok := dst["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst["details"]) - if dst["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst["boat"]) - } + _, ok = det["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst["boat"].(string), "Expected boat string, got %v", dst["boat"]) // This is one test that is different from CoalesceTables. Because hole // is a nil value and it's not removed it's still present. - if _, ok = dst["hole"]; !ok { - t.Error("The hole no longer exists.") - } + _, ok = dst["hole"] + assert.True(t, ok, "The hole no longer exists.") dst2 := map[string]any{ "name": "Ishmael", @@ -626,44 +548,22 @@ func TestMergeTables(t *testing.T) { // this happens when the --reuse-values flag is set but the chart has no modifications yet MergeTables(dst2, nil) - if dst2["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst2["name"]) - } + assert.Equal(t, "Ishmael", dst2["name"], "Unexpected name: %s", dst2["name"]) addr2, ok := dst2["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr2["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr2["street"]) - } - - if addr2["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr2["city"]) - } - - if addr2["country"].(string) != "US" { - t.Errorf("Unexpected Country: %v", addr2["country"]) - } - - if det2, ok := dst2["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst2["details"]) - } else if _, ok := det2["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst2["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst2["boat"]) - } - - if dst2["hole"].(string) != "black" { - t.Errorf("Expected hole string, got %v", dst2["boat"]) - } - - if dst2["nilval"] != nil { - t.Error("Expected nilvalue to have nil value but it does not") - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr2["street"].(string), "Unexpected address: %v", addr2["street"]) + assert.Equal(t, "Nantucket", addr2["city"].(string), "Unexpected city: %v", addr2["city"]) + assert.Equal(t, "US", addr2["country"].(string), "Unexpected Country: %v", addr2["country"]) + + det2, ok := dst2["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst2["details"]) + + _, ok = det2["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst2["boat"].(string), "Expected boat string, got %v", dst2["boat"]) + assert.Equal(t, "black", dst2["hole"].(string), "Expected hole string, got %v", dst2["hole"]) + assert.Nil(t, dst2["nilval"], "Expected nilvalue to have nil value but it does not") } func TestCoalesceValuesWarnings(t *testing.T) { @@ -716,9 +616,7 @@ func TestCoalesceValuesWarnings(t *testing.T) { } _, err := coalesce(printf, c, vals, "", false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) t.Logf("vals: %v", vals) assert.Contains(t, warnings, "warning: skipped value for level1.level2.level3.boat: Not a table.") @@ -926,7 +824,6 @@ func TestCoalesceValuesSubchartNilCleanedWhenUserPartiallyOverrides(t *testing.T keyMapping, ok := childVals["keyMapping"].(map[string]any) is.True(ok, "keyMapping should be a map") - is.Equal("sha256", keyMapping["format"], "User override should be preserved") _, ok = keyMapping["password"] diff --git a/pkg/chart/common/util/jsonschema_test.go b/pkg/chart/common/util/jsonschema_test.go index 838d152a1..90fdc9b11 100644 --- a/pkg/chart/common/util/jsonschema_test.go +++ b/pkg/chart/common/util/jsonschema_test.go @@ -20,75 +20,47 @@ import ( "net/http" "net/http/httptest" "os" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" ) func TestValidateAgainstSingleSchema(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values.schema.json") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - if err := ValidateAgainstSingleSchema(values, schema); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + schema, err := os.ReadFile("./testdata/test-values.schema.json") + require.NoError(t, err, "Error reading YAML file") + assert.NoErrorf(t, ValidateAgainstSingleSchema(values, schema), "Error validating Values against Schema") } func TestValidateAgainstInvalidSingleSchema(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values-invalid.schema.json") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - var errString string - if err := ValidateAgainstSingleSchema(values, schema); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } + schema, err := os.ReadFile("./testdata/test-values-invalid.schema.json") + require.NoError(t, err, "Error reading YAML file") expectedErrString := `"file:///values.schema.json#" is not valid against metaschema: jsonschema validation failed with 'https://json-schema.org/draft/2020-12/schema#' - at '': got number, want boolean or object` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSingleSchema(values, schema), expectedErrString) } func TestValidateAgainstSingleSchemaNegative(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values-negative.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values.schema.json") - if err != nil { - t.Fatalf("Error reading JSON file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - var errString string - if err := ValidateAgainstSingleSchema(values, schema); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } + schema, err := os.ReadFile("./testdata/test-values.schema.json") + require.NoError(t, err, "Error reading JSON file") expectedErrString := `- at '': missing property 'employmentInfo' - at '/age': minimum: got -5, want 0 ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSingleSchema(values, schema), expectedErrString) } const subchartSchema = `{ @@ -145,9 +117,7 @@ func TestValidateAgainstSchema(t *testing.T) { }, } - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + assert.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "Error validating Values against Schema") } func TestValidateAgainstSchemaNegative(t *testing.T) { @@ -170,19 +140,10 @@ func TestValidateAgainstSchemaNegative(t *testing.T) { "subchart": map[string]any{}, } - var errString string - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } - expectedErrString := `subchart: - at '': missing property 'age' ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSchema(chrt, vals), expectedErrString) } func TestValidateAgainstSchema2020(t *testing.T) { @@ -207,9 +168,7 @@ func TestValidateAgainstSchema2020(t *testing.T) { }, } - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + assert.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "Error validating Values against Schema") } func TestValidateAgainstSchema2020Negative(t *testing.T) { @@ -234,20 +193,11 @@ func TestValidateAgainstSchema2020Negative(t *testing.T) { }, } - var errString string - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } - expectedErrString := `subchart: - at '/data': no items match contains schema - at '/data/0': got number, want string ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSchema(chrt, vals), expectedErrString) } func TestHTTPURLLoader_Load(t *testing.T) { @@ -262,12 +212,8 @@ func TestHTTPURLLoader_Load(t *testing.T) { loader := newHTTPURLLoader() result, err := loader.Load(server.URL) - if err != nil { - t.Fatalf("Expected no error, got: %v", err) - } - if result == nil { - t.Fatal("Expected result to be non-nil") - } + require.NoError(t, err, "Expected no error, got") + require.NotNil(t, result, "Expected result to be non-nil") }) t.Run("HTTP error status", func(t *testing.T) { @@ -278,12 +224,8 @@ func TestHTTPURLLoader_Load(t *testing.T) { loader := newHTTPURLLoader() _, err := loader.Load(server.URL) - if err == nil { - t.Fatal("Expected error for HTTP 404") - } - if !strings.Contains(err.Error(), "404") { - t.Errorf("Expected error message to contain '404', got: %v", err) - } + require.Error(t, err, "Expected error for HTTP 404") + assert.ErrorContains(t, err, "404", "Expected error message to contain '404'") }) } @@ -295,9 +237,7 @@ func TestValidateAgainstSingleSchema_UnresolvedURN_Ignored(t *testing.T) { "$ref": "urn:example:helm:schemas:v1:helm-schema-validation-conditions:v1/helmSchemaValidation-true" }`) vals := map[string]any{"any": "value"} - if err := ValidateAgainstSingleSchema(vals, schema); err != nil { - t.Fatalf("expected no error when URN unresolved is ignored, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSingleSchema(vals, schema), "expected no error when URN unresolved is ignored, got") } // Non-regression tests for https://github.com/helm/helm/issues/31202 @@ -323,14 +263,10 @@ func TestValidateAgainstSchema_MissingSubchartValues_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (missing subchart values): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (missing subchart values)") }() - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Fatalf("expected no error when subchart values are missing, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "expected no error when subchart values are missing, got") } func TestValidateAgainstSchema_SubchartNil_NoPanic(t *testing.T) { @@ -351,14 +287,10 @@ func TestValidateAgainstSchema_SubchartNil_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (nil subchart values): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (nil subchart values)") }() - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Fatalf("expected no error when subchart values are nil, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "expected no error when subchart values are nil, got") } func TestValidateAgainstSchema_InvalidSubchartValuesType_NoPanic(t *testing.T) { @@ -379,13 +311,9 @@ func TestValidateAgainstSchema_InvalidSubchartValuesType_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (invalid subchart values type): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (invalid subchart values type)") }() // We expect a non-nil error (invalid type), but crucially no panic. - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("expected an error when subchart values have invalid type, got nil") - } + require.Error(t, ValidateAgainstSchema(chrt, vals), "expected an error when subchart values have invalid type, got nil") } diff --git a/pkg/cmd/completion_test.go b/pkg/cmd/completion_test.go index 399ff1f0c..219d1eed0 100644 --- a/pkg/cmd/completion_test.go +++ b/pkg/cmd/completion_test.go @@ -21,6 +21,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" @@ -44,9 +46,7 @@ func checkFileCompletion(t *testing.T, cmdName string, shouldBePerformed bool) { testcmd := fmt.Sprintf("__complete %s ''", cmdName) _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } + require.NoError(t, err) if !strings.Contains(out, "ShellCompDirectiveNoFileComp") != shouldBePerformed { if shouldBePerformed { t.Errorf("Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) From 2f5a33fb77daca9ade910ed7fe557e3e85fd77f6 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 102/161] chore(pkg): refactor: convert tests to testify assert/require part 10 #### Description refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/cmd/create_test.go | 155 +++++++---------------- pkg/storage/storage_test.go | 242 +++++++++++++----------------------- 2 files changed, 134 insertions(+), 263 deletions(-) diff --git a/pkg/cmd/create_test.go b/pkg/cmd/create_test.go index 1a1289775..6f25d4c63 100644 --- a/pkg/cmd/create_test.go +++ b/pkg/cmd/create_test.go @@ -22,6 +22,9 @@ import ( "slices" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chartv3 "helm.sh/helm/v4/internal/chart/v3" chartutilv3 "helm.sh/helm/v4/internal/chart/v3/util" "helm.sh/helm/v4/internal/gates" @@ -39,38 +42,25 @@ func TestCreateCmd(t *testing.T) { cname := "testchart" // Run a create - if _, _, err := executeActionCommand("create " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv2.APIVersionV2 { - t.Errorf("Wrong API version: %q", apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv2.APIVersionV2, apiVersion, "Wrong API version: %q", apiVersion) } func TestCreateStarterCmd(t *testing.T) { @@ -123,15 +113,11 @@ func TestCreateStarterCmd(t *testing.T) { } else { dest, err = chartutil.Create("starterchart", starterchart) } - if err != nil { - t.Fatalf("Could not create chart: %s", err) - } + require.NoError(t, err, "Could not create chart") t.Logf("Created %s", dest) tplpath := filepath.Join(starterchart, "starterchart", "templates", "foo.tpl") - if err := os.WriteFile(tplpath, []byte("test"), 0o644); err != nil { - t.Fatalf("Could not write template: %s", err) - } + require.NoErrorf(t, os.WriteFile(tplpath, []byte("test"), 0o644), "Could not write template") // Build the command starterArg := "starterchart" @@ -147,51 +133,36 @@ func TestCreateStarterCmd(t *testing.T) { cmd += " " + cname // Run create - if _, _, err := executeActionCommand(cmd); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err = executeActionCommand(cmd) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") // Load and verify the chart c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) chartName := acc.Name() metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } + require.True(t, ok, "APIVersion not found in metadata") var templates []string for _, tpl := range acc.Templates() { templates = append(templates, tpl.Name) } - if chartName != cname { - t.Errorf("Expected %q name, got %q", cname, chartName) - } - if apiVersion != tt.expectedVersion { - t.Errorf("Wrong API version: expected %q, got %q", tt.expectedVersion, apiVersion) - } + assert.Equal(t, cname, chartName, "Expected %q name, got %q", cname, chartName) + assert.Equal(t, tt.expectedVersion, apiVersion, "Wrong API version: expected %q, got %q", tt.expectedVersion, apiVersion) // Verify custom template exists found := slices.Contains(templates, "templates/foo.tpl") - if !found { - t.Error("Did not find foo.tpl") - } + assert.True(t, found, "Did not find foo.tpl") }) } } @@ -207,38 +178,25 @@ func TestCreateCmdChartAPIVersionV2(t *testing.T) { cname := "testchart" // Run a create with explicit v2 - if _, _, err := executeActionCommand("create --chart-api-version=v2 " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create --chart-api-version=v2 " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv2.APIVersionV2 { - t.Errorf("Wrong API version: expected %q, got %q", chartv2.APIVersionV2, apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv2.APIVersionV2, apiVersion, "Wrong API version: expected %q, got %q", chartv2.APIVersionV2, apiVersion) } func TestCreateCmdChartAPIVersionV3(t *testing.T) { @@ -248,38 +206,25 @@ func TestCreateCmdChartAPIVersionV3(t *testing.T) { cname := "testchart" // Run a create with v3 - if _, _, err := executeActionCommand("create --chart-api-version=v3 " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create --chart-api-version=v3 " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv3.APIVersionV3 { - t.Errorf("Wrong API version: expected %q, got %q", chartv3.APIVersionV3, apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv3.APIVersionV3, apiVersion, "Wrong API version: expected %q, got %q", chartv3.APIVersionV3, apiVersion) } func TestCreateCmdInvalidChartAPIVersion(t *testing.T) { @@ -289,12 +234,8 @@ func TestCreateCmdInvalidChartAPIVersion(t *testing.T) { // Run a create with invalid version _, _, err := executeActionCommand("create --chart-api-version=v1 " + cname) - if err == nil { - t.Fatal("Expected error for invalid API version, got nil") - } + require.Error(t, err, "Expected error for invalid API version, got nil") expectedErr := "unsupported chart API version: v1 (supported: v2, v3)" - if err.Error() != expectedErr { - t.Errorf("Expected error %q, got %q", expectedErr, err.Error()) - } + assert.EqualError(t, err, expectedErr, "Expected error %q, got %q", expectedErr, err.Error()) } diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 8ecee447f..821eccb81 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -19,11 +19,11 @@ package storage import ( "context" "errors" - "fmt" "log/slog" "reflect" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" @@ -42,16 +42,14 @@ func TestStorageCreate(t *testing.T) { Version: 1, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") // fetch the release res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") + require.NoError(t, err, "QueryRelease") // verify the fetched and created release are the same - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) } func TestStorageUpdate(t *testing.T) { @@ -65,20 +63,18 @@ func TestStorageUpdate(t *testing.T) { Status: common.StatusDeployed, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") // modify the release rls.Info.Status = common.StatusUninstalled - assertErrNil(t.Fatal, storage.Update(rls), "UpdateRelease") + require.NoError(t, storage.Update(rls), "UpdateRelease") // retrieve the updated release res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") + require.NoError(t, err, "QueryRelease") // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) } func TestStorageDelete(t *testing.T) { @@ -95,34 +91,26 @@ func TestStorageDelete(t *testing.T) { Version: 2, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") - assertErrNil(t.Fatal, storage.Create(rls2), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls2), "StoreRelease") // delete the release res, err := storage.Delete(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "DeleteRelease") + require.NoError(t, err, "DeleteRelease") // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) hist, err := storage.History(rls.Name) - if err != nil { - t.Errorf("unexpected error: %s", err) - } + require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) // We have now deleted one of the two records. - if len(rhist) != 1 { - t.Errorf("expected 1 record for deleted release version, got %d", len(hist)) - } + assert.Len(t, rhist, 1, "expected 1 record for deleted release version, got %d", len(hist)) - if rhist[0].Version != 2 { - t.Errorf("Expected version to be 2, got %d", rhist[0].Version) - } + assert.Equal(t, 2, rhist[0].Version, "Expected version to be 2, got %d", rhist[0].Version) } func TestStorageList(t *testing.T) { @@ -141,13 +129,13 @@ func TestStorageList(t *testing.T) { rls6 := ReleaseTestData{Name: "happy-liger", Status: common.StatusUninstalled}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'rls0'") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'rls1'") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'rls2'") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'rls3'") - assertErrNil(t.Fatal, storage.Create(rls4), "Storing release 'rls4'") - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'rls5'") - assertErrNil(t.Fatal, storage.Create(rls6), "Storing release 'rls6'") + require.NoError(t, storage.Create(rls0), "Storing release 'rls0'") + require.NoError(t, storage.Create(rls1), "Storing release 'rls1'") + require.NoError(t, storage.Create(rls2), "Storing release 'rls2'") + require.NoError(t, storage.Create(rls3), "Storing release 'rls3'") + require.NoError(t, storage.Create(rls4), "Storing release 'rls4'") + require.NoError(t, storage.Create(rls5), "Storing release 'rls5'") + require.NoError(t, storage.Create(rls6), "Storing release 'rls6'") } var listTests = []struct { @@ -164,14 +152,9 @@ func TestStorageList(t *testing.T) { for _, tt := range listTests { list, err := tt.ListFunc() - assertErrNil(t.Fatal, err, tt.Description) + require.NoError(t, err, tt.Description) // verify the count of releases returned - if len(list) != tt.NumExpected { - t.Errorf("ListReleases(%s): expected %d, actual %d", - tt.Description, - tt.NumExpected, - len(list)) - } + assert.Len(t, list, tt.NumExpected, "ListReleases(%s): expected %d, actual %d", tt.Description, tt.NumExpected, len(list)) } } @@ -190,32 +173,24 @@ func TestStorageDeployed(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls, err := storage.Last(name) - if err != nil { - t.Fatalf("Failed to query for deployed release: %s\n", err) - } + require.NoError(t, err, "Failed to query for deployed release") rel, err := releaserToV1Release(rls) require.NoError(t, err) - switch { - case rls == nil: - t.Fatal("Release is nil") - case rel.Name != name: - t.Fatalf("Expected release name %q, actual %q\n", name, rel.Name) - case rel.Version != vers: - t.Fatalf("Expected release version %d, actual %d\n", vers, rel.Version) - case rel.Info.Status != common.StatusDeployed: - t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) - } + require.NotNil(t, rls, "Release is nil") + require.Equal(t, name, rel.Name, "Expected release name %q, actual %q\n", name, rel.Name) + require.Equal(t, vers, rel.Version, "Expected release version %d, actual %d\n", vers, rel.Version) + require.Equal(t, common.StatusDeployed, rel.Info.Status, "Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) } func TestStorageDeployedWithCorruption(t *testing.T) { @@ -233,32 +208,24 @@ func TestStorageDeployedWithCorruption(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 2, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls, err := storage.Deployed(name) - if err != nil { - t.Fatalf("Failed to query for deployed release: %s\n", err) - } + require.NoError(t, err, "Failed to query for deployed release") rel, err := releaserToV1Release(rls) require.NoError(t, err) - switch { - case rls == nil: - t.Fatal("Release is nil") - case rel.Name != name: - t.Fatalf("Expected release name %q, actual %q\n", name, rel.Name) - case rel.Version != vers: - t.Fatalf("Expected release version %d, actual %d\n", vers, rel.Version) - case rel.Info.Status != common.StatusDeployed: - t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) - } + require.NotNil(t, rls, "Release is nil") + require.Equal(t, name, rel.Name, "Expected release name %q, actual %q\n", name, rel.Name) + require.Equal(t, vers, rel.Version, "Expected release version %d, actual %d\n", vers, rel.Version) + require.Equal(t, common.StatusDeployed, rel.Info.Status, "Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) } func TestStorageHistory(t *testing.T) { @@ -275,21 +242,17 @@ func TestStorageHistory(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() h, err := storage.History(name) - if err != nil { - t.Fatalf("Failed to query for release history (%q): %s\n", name, err) - } - if len(h) != 4 { - t.Fatalf("Release history (%q) is empty\n", name) - } + require.NoError(t, err, "Failed to query for release history (%q)", name) + require.Len(t, h, 4, "Release history (%q) is empty\n", name) } var errMaxHistoryMockDriverSomethingHappened = errors.New("something happened") @@ -336,16 +299,14 @@ func TestMaxHistoryErrorHandling(t *testing.T) { rls1 := ReleaseTestData{Name: name, Version: 1, Status: common.StatusSuperseded}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Driver.Create(makeKey(rls1.Name, rls1.Version), rls1), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Driver.Create(makeKey(rls1.Name, rls1.Version), rls1), "Storing release 'angry-bird' (v1)") } setup() rls2 := ReleaseTestData{Name: name, Version: 2, Status: common.StatusSuperseded}.ToRelease() wantErr := errMaxHistoryMockDriverSomethingHappened gotErr := storage.Create(rls2) - if !errors.Is(gotErr, wantErr) { - t.Fatalf("Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr) - } + require.ErrorIs(t, gotErr, wantErr, "Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr) } func TestStorageRemoveLeastRecent(t *testing.T) { @@ -365,27 +326,25 @@ func TestStorageRemoveLeastRecent(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() // Because we have not set a limit, we expect 4. expect := 4 - if hist, err := storage.History(name); err != nil { - t.Fatal(err) - } else if len(hist) != expect { - t.Fatalf("expected %d items in history, got %d", expect, len(hist)) - } + hist, err := storage.History(name) + require.NoError(t, err) + require.Equal(t, len(hist), expect, "expected %d items in history, got %d", expect, len(hist)) storage.MaxHistory = 3 rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusDeployed}.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)") + require.NoError(t, storage.Create(rls5), "Storing release 'angry-bird' (v5)") // On inserting the 5th record, we expect two records to be pruned from history. - hist, err := storage.History(name) + hist, err = storage.History(name) require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) @@ -399,9 +358,8 @@ func TestStorageRemoveLeastRecent(t *testing.T) { // We expect the existing records to be 3, 4, and 5. for i, item := range rhist { v := item.Version - if expect := i + 3; v != expect { - t.Errorf("Expected release %d, got %d", expect, v) - } + expect := i + 3 + assert.Equalf(t, v, expect, "Expected release %d, got %d", expect, v) } } @@ -420,22 +378,21 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusFailed}.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)") + require.NoError(t, storage.Create(rls5), "Storing release 'angry-bird' (v5)") // On inserting the 5th record, we expect a total of 3 releases, but we expect version 2 // (the only deployed release), to still exist hist, err := storage.History(name) - if err != nil { - t.Fatal(err) - } else if len(hist) != storage.MaxHistory { + require.NoError(t, err) + if len(hist) != storage.MaxHistory { rhist, err := releaseListToV1List(hist) require.NoError(t, err) for _, item := range rhist { @@ -453,9 +410,7 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { rhist, err := releaseListToV1List(hist) require.NoError(t, err) for _, item := range rhist { - if !expectedVersions[item.Version] { - t.Errorf("Release version %d, found when not expected", item.Version) - } + assert.Truef(t, expectedVersions[item.Version], "Release version %d, found when not expected", item.Version) } } @@ -473,25 +428,21 @@ func TestStorageLast(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() h, err := storage.Last(name) - if err != nil { - t.Fatalf("Failed to query for release history (%q): %s\n", name, err) - } + require.NoError(t, err, "Failed to query for release history (%q)", name) rel, err := releaserToV1Release(h) require.NoError(t, err) - if rel.Version != 4 { - t.Errorf("Expected revision 4, got %d", rel.Version) - } + assert.Equal(t, 4, rel.Version, "Expected revision 4, got %d", rel.Version) } // TestUpgradeInitiallyFailedReleaseWithHistoryLimit tests a case when there are no deployed release yet, but history limit has been @@ -511,47 +462,34 @@ func TestUpgradeInitiallyFailedReleaseWithHistoryLimit(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") hist, err := storage.History(name) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) wantHistoryLen := 4 - if len(hist) != wantHistoryLen { - t.Fatalf("expected history of release %q to contain %d releases, got %d", name, wantHistoryLen, len(hist)) - } + require.Len(t, hist, wantHistoryLen, "expected history of release %q to contain %d releases, got %d", name, wantHistoryLen, len(hist)) } setup() rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusFailed}.ToRelease() - err := storage.Create(rls5) - if err != nil { - t.Fatalf("Failed to create a new release version: %s", err) - } + require.NoError(t, storage.Create(rls5), "Failed to create a new release version") hist, err := storage.History(name) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) for i, rel := range rhist { wantVersion := i + 2 - if rel.Version != wantVersion { - t.Fatalf("Expected history release %d version to equal %d, got %d", i+1, wantVersion, rel.Version) - } + require.Equal(t, wantVersion, rel.Version, "Expected history release %d version to equal %d, got %d", i+1, wantVersion, rel.Version) wantStatus := common.StatusFailed - if rel.Info.Status != wantStatus { - t.Fatalf("Expected history release %d status to equal %q, got %q", i+1, wantStatus, rel.Info.Status) - } + require.Equal(t, wantStatus, rel.Info.Status, "Expected history release %d status to equal %q, got %q", i+1, wantStatus, rel.Info.Status) } } @@ -573,21 +511,13 @@ func (test ReleaseTestData) ToRelease() *rspb.Release { } } -func assertErrNil(eh func(args ...any), err error, message string) { - if err != nil { - eh(fmt.Sprintf("%s: %q", message, err)) - } -} - func TestStorageGetsLoggerFromDriver(t *testing.T) { d := driver.NewMemory() l := &mockSLogHandler{} d.SetLogger(l) s := Init(d) _, _ = s.Get("doesnt-matter", 123) - if !l.Called { - t.Fatal("Expected storage to use driver's logger, but it did not") - } + require.True(t, l.Called, "Expected storage to use driver's logger, but it did not") } type mockSLogHandler struct { From dc3e3a5e7efadff49fd26eac511cf18801af0ebc Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 103/161] chore(pkg): refactor: convert tests to testify assert/require part 11 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/action/rollback_test.go | 3 +- pkg/downloader/manager_test.go | 217 +++++++++------------------------ pkg/kube/ready_test.go | 202 +++++++++++------------------- 3 files changed, 128 insertions(+), 294 deletions(-) diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index 01419341b..7ffd90d25 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -78,8 +78,7 @@ func TestRollback_WaitOptionsPassedDownstream(t *testing.T) { // Access the underlying FailingKubeClient to check recorded options failer := config.KubeClient.(*kubefake.FailingKubeClient) - err := client.Run(rel.Name) - req.NoError(err) + req.NoError(client.Run(rel.Name)) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index e0cea0cd2..00cb5b668 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -17,7 +17,6 @@ package downloader import ( "bytes" - "errors" "io/fs" "os" "path/filepath" @@ -50,9 +49,7 @@ func TestVersionEquals(t *testing.T) { } for _, tt := range tests { - if versionEquals(tt.v1, tt.v2) != tt.expect { - t.Errorf("%s: failed comparison of %q and %q (expect equal: %t)", tt.name, tt.v1, tt.v2, tt.expect) - } + assert.Equal(t, tt.expect, versionEquals(tt.v1, tt.v2), "%s: failed comparison of %q and %q (expect equal: %t)", tt.name, tt.v1, tt.v2, tt.expect) } } @@ -64,84 +61,46 @@ func TestFindChartURL(t *testing.T) { RepositoryCache: repoCache, } repos, err := m.loadChartRepositories() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) name := "alpine" version := "0.1.0" repoURL := "http://example.com/charts" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if churl != "https://charts.helm.sh/stable/alpine-0.1.0.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } - if insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } + assert.Equal(t, "https://charts.helm.sh/stable/alpine-0.1.0.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) + assert.False(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) name = "tlsfoo" version = "1.2.3" repoURL = "https://example-https-insecureskiptlsverify.com" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } - if churl != "https://example.com/tlsfoo-1.2.3.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } + assert.True(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) + assert.Equal(t, "https://example.com/tlsfoo-1.2.3.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) name = "foo" version = "1.2.3" repoURL = "http://example.com/helm" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if churl != "http://example.com/helm/charts/foo-1.2.3.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } - if insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } + assert.Equal(t, "http://example.com/helm/charts/foo-1.2.3.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) + assert.False(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) } func TestGetRepoNames(t *testing.T) { @@ -217,15 +176,11 @@ func TestGetRepoNames(t *testing.T) { t.Fatal(err) } - if tt.err { - t.Fatalf("Expected error in test %q", tt.name) - } + require.False(t, tt.err, "Expected error in test %q", tt.name) // m1 and m2 are the maps we want to compare eq := reflect.DeepEqual(l, tt.expect) - if !eq { - t.Errorf("%s: expected map %v, got %v", tt.name, l, tt.name) - } + assert.True(t, eq, "%s: expected map %v, got %v", tt.name, l, tt.name) } } @@ -238,20 +193,12 @@ func TestDownloadAll(t *testing.T) { ChartPath: chartPath, } signtest, err := loader.LoadDir(filepath.Join("testdata", "signtest")) - if err != nil { - t.Fatal(err) - } - if err := chartutil.SaveDir(signtest, filepath.Join(chartPath, "testdata")); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + require.NoError(t, chartutil.SaveDir(signtest, filepath.Join(chartPath, "testdata"))) local, err := loader.LoadDir(filepath.Join("testdata", "local-subchart")) - if err != nil { - t.Fatal(err) - } - if err := chartutil.SaveDir(local, filepath.Join(chartPath, "charts")); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + require.NoError(t, chartutil.SaveDir(local, filepath.Join(chartPath, "charts"))) signDep := &chart.Dependency{ Name: signtest.Name(), @@ -265,16 +212,11 @@ func TestDownloadAll(t *testing.T) { } // create a 'tmpcharts' directory to test #5567 - if err := os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0o755); err != nil { - t.Fatal(err) - } - if err := m.downloadAll([]*chart.Dependency{signDep, localDep}); err != nil { - t.Error(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0o755)) + require.NoError(t, m.downloadAll([]*chart.Dependency{signDep, localDep})) - if _, err := os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")); errors.Is(err, fs.ErrNotExist) { - t.Error(err) - } + _, err = os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")) + require.NotErrorIs(t, err, fs.ErrNotExist) // A chart with a bad name like this cannot be loaded and saved. Handling in // the loading and saving will return an error about the invalid name. In @@ -283,24 +225,15 @@ func TestDownloadAll(t *testing.T) { description: A Helm chart for Kubernetes name: ../bad-local-subchart version: 0.1.0` - if err := os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0o755); err != nil { - t.Fatal(err) - } - err = os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0o644) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0o644)) badLocalDep := &chart.Dependency{ Name: "../bad-local-subchart", Repository: "file://./testdata/bad-local-subchart", Version: "0.1.0", } - - err = m.downloadAll([]*chart.Dependency{badLocalDep}) - if err == nil { - t.Fatal("Expected error for bad dependency name") - } + require.Error(t, m.downloadAll([]*chart.Dependency{badLocalDep}), "Expected error for bad dependency name") } func TestUpdateBeforeBuild(t *testing.T) { @@ -310,9 +243,7 @@ func TestUpdateBeforeBuild(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -325,9 +256,7 @@ func TestUpdateBeforeBuild(t *testing.T) { APIVersion: "v1", }, } - if err := chartutil.SaveDir(d, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(d, dir())) // Save a chart c := &chart.Chart{ Metadata: &chart.Metadata{ @@ -341,9 +270,7 @@ func TestUpdateBeforeBuild(t *testing.T) { }}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Set-up a manager b := bytes.NewBuffer(nil) @@ -360,13 +287,8 @@ func TestUpdateBeforeBuild(t *testing.T) { } // Update before Build. see issue: https://github.com/helm/helm/issues/7101 - if err := m.Update(); err != nil { - t.Fatal(err) - } - - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Update()) + require.NoError(t, m.Build()) } // TestUpdateWithNoRepo is for the case of a dependency that has no repo listed. @@ -379,9 +301,7 @@ func TestUpdateWithNoRepo(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -407,16 +327,12 @@ func TestUpdateWithNoRepo(t *testing.T) { }}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Save dependent chart into the parents charts directory. If the chart is // not in the charts directory Helm will return an error that it is not // found. - if err := chartutil.SaveDir(d, dir(c.Metadata.Name, "charts")); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(d, dir(c.Metadata.Name, "charts"))) // Set-up a manager b := bytes.NewBuffer(nil) @@ -433,9 +349,7 @@ func TestUpdateWithNoRepo(t *testing.T) { } // Test the update - if err := m.Update(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Update()) } // This function is the skeleton test code of failing tests for #6416 and #6871 and bugs due to #5874. @@ -452,9 +366,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -479,9 +391,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe Dependencies: []*chart.Dependency{&dep}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Set-up a manager b := bytes.NewBuffer(nil) @@ -500,14 +410,10 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe } // First build will update dependencies and create Chart.lock file. - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Build()) // Second build should be passed. See PR #6655. - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Build()) } func TestBuild_WithoutOptionalFields(t *testing.T) { @@ -573,9 +479,8 @@ func TestErrRepoNotFound_Error(t *testing.T) { e := ErrRepoNotFound{ Repos: tt.fields.Repos, } - if got := e.Error(); got != tt.want { - t.Errorf("Error() = %v, want %v", got, tt.want) - } + got := e.Error() + assert.EqualErrorf(t, e, tt.want, "Error() = %v, want %v", got, tt.want) }) } } @@ -601,12 +506,8 @@ func TestKey(t *testing.T) { for _, tt := range tests { o, err := key(tt.name) - if err != nil { - t.Fatalf("unable to generate key for %q with error: %s", tt.name, err) - } - if o != tt.expect { - t.Errorf("wrong key name generated for %q, expected %q but got %q", tt.name, tt.expect, o) - } + require.NoError(t, err, "unable to generate key for %q", tt.name) + assert.Equal(t, tt.expect, o, "wrong key name generated for %q, expected %q but got %q", tt.name, tt.expect, o) } } @@ -697,8 +598,7 @@ func TestWriteLock(t *testing.T) { t.Run("v2 lock file", func(t *testing.T) { dir := t.TempDir() - err := writeLock(dir, lock, false) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, false)) lockfilePath := filepath.Join(dir, "Chart.lock") _, err = os.Stat(lockfilePath) @@ -716,8 +616,7 @@ func TestWriteLock(t *testing.T) { t.Run("v1 lock file", func(t *testing.T) { dir := t.TempDir() - err := writeLock(dir, lock, true) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, true)) lockfilePath := filepath.Join(dir, "requirements.lock") _, err = os.Stat(lockfilePath) @@ -737,9 +636,7 @@ func TestWriteLock(t *testing.T) { dir := t.TempDir() lockfilePath := filepath.Join(dir, "Chart.lock") require.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0o644)) - - err = writeLock(dir, lock, false) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, false)) content, err := os.ReadFile(lockfilePath) require.NoError(t, err) @@ -753,17 +650,13 @@ func TestWriteLock(t *testing.T) { lockfilePath := filepath.Join(dir, "Chart.lock") require.NoError(t, os.Symlink(dummyFile, lockfilePath)) - - err = writeLock(dir, lock, false) - assert.ErrorContains(t, err, "the Chart.lock file is a symlink to") + assert.ErrorContains(t, writeLock(dir, lock, false), "the Chart.lock file is a symlink to") }) t.Run("chart path is not a directory", func(t *testing.T) { dir := t.TempDir() filePath := filepath.Join(dir, "not-a-dir") require.NoError(t, os.WriteFile(filePath, []byte("file"), 0o644)) - - err = writeLock(filePath, lock, false) - assert.Error(t, err) + assert.Error(t, writeLock(filePath, lock, false)) }) } diff --git a/pkg/kube/ready_test.go b/pkg/kube/ready_test.go index fc3ac9409..01f6db3cb 100644 --- a/pkg/kube/ready_test.go +++ b/pkg/kube/ready_test.go @@ -19,6 +19,8 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -90,18 +92,15 @@ func Test_ReadyChecker_IsReady_Pod(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), tt.pod, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Pod error: %v", err) - return - } + _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), tt.pod, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Pod error") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -162,17 +161,12 @@ func Test_ReadyChecker_IsReady_Job(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.BatchV1().Jobs(defaultNamespace).Create(t.Context(), tt.job, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Job error: %v", err) - return - } + _, err := c.client.BatchV1().Jobs(defaultNamespace).Create(t.Context(), tt.job, metav1.CreateOptions{}) + + require.NoError(t, err, "Failed to create Job") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -236,21 +230,15 @@ func Test_ReadyChecker_IsReady_Deployment(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().Deployments(defaultNamespace).Create(t.Context(), tt.deployment, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Deployment error: %v", err) - return - } - if _, err := c.client.AppsV1().ReplicaSets(defaultNamespace).Create(t.Context(), tt.replicaSet, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create ReplicaSet error: %v", err) - return - } + _, err := c.client.AppsV1().Deployments(defaultNamespace).Create(t.Context(), tt.deployment, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Deployment") + + _, err = c.client.AppsV1().ReplicaSets(defaultNamespace).Create(t.Context(), tt.replicaSet, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create ReplicaSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -311,17 +299,12 @@ func Test_ReadyChecker_IsReady_PersistentVolumeClaim(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().PersistentVolumeClaims(defaultNamespace).Create(t.Context(), tt.pvc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create PersistentVolumeClaim error: %v", err) - return - } + _, err := c.client.CoreV1().PersistentVolumeClaims(defaultNamespace).Create(t.Context(), tt.pvc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create PersistentVolumeClaim") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -382,17 +365,12 @@ func Test_ReadyChecker_IsReady_Service(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().Services(defaultNamespace).Create(t.Context(), tt.svc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Service error: %v", err) - return - } + _, err := c.client.CoreV1().Services(defaultNamespace).Create(t.Context(), tt.svc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Service") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -453,17 +431,12 @@ func Test_ReadyChecker_IsReady_DaemonSet(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().DaemonSets(defaultNamespace).Create(t.Context(), tt.ds, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create DaemonSet error: %v", err) - return - } + _, err := c.client.AppsV1().DaemonSets(defaultNamespace).Create(t.Context(), tt.ds, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create DaemonSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -524,17 +497,12 @@ func Test_ReadyChecker_IsReady_StatefulSet(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().StatefulSets(defaultNamespace).Create(t.Context(), tt.ss, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create StatefulSet error: %v", err) - return - } + _, err := c.client.AppsV1().StatefulSets(defaultNamespace).Create(t.Context(), tt.ss, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create StatefulSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -610,17 +578,12 @@ func Test_ReadyChecker_IsReady_ReplicationController(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().ReplicationControllers(defaultNamespace).Create(t.Context(), tt.rc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create ReplicationController error: %v", err) - return - } + _, err := c.client.CoreV1().ReplicationControllers(defaultNamespace).Create(t.Context(), tt.rc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create ReplicationController") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -683,12 +646,8 @@ func Test_ReadyChecker_IsReady_ReplicaSet(t *testing.T) { } // got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -755,9 +714,8 @@ func Test_ReadyChecker_deploymentReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.deploymentReady(tt.args.rs, tt.args.dep); got != tt.want { - t.Errorf("deploymentReady() = %v, want %v", got, tt.want) - } + got := c.deploymentReady(tt.args.rs, tt.args.dep) + assert.Equalf(t, tt.want, got, "deploymentReady() = %v, want %v", got, tt.want) }) } } @@ -789,9 +747,8 @@ func Test_ReadyChecker_replicaSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.replicaSetReady(tt.args.rs); got != tt.want { - t.Errorf("replicaSetReady() = %v, want %v", got, tt.want) - } + got := c.replicaSetReady(tt.args.rs) + assert.Equalf(t, tt.want, got, "replicaSetReady() = %v, want %v", got, tt.want) }) } } @@ -823,9 +780,8 @@ func Test_ReadyChecker_replicationControllerReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.replicationControllerReady(tt.args.rc); got != tt.want { - t.Errorf("replicationControllerReady() = %v, want %v", got, tt.want) - } + got := c.replicationControllerReady(tt.args.rc) + assert.Equalf(t, tt.want, got, "replicationControllerReady() = %v, want %v", got, tt.want) }) } } @@ -878,9 +834,8 @@ func Test_ReadyChecker_daemonSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.daemonSetReady(tt.args.ds); got != tt.want { - t.Errorf("daemonSetReady() = %v, want %v", got, tt.want) - } + got := c.daemonSetReady(tt.args.ds) + assert.Equalf(t, tt.want, got, "daemonSetReady() = %v, want %v", got, tt.want) }) } } @@ -954,9 +909,8 @@ func Test_ReadyChecker_statefulSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.statefulSetReady(tt.args.sts); got != tt.want { - t.Errorf("statefulSetReady() = %v, want %v", got, tt.want) - } + got := c.statefulSetReady(tt.args.sts) + assert.Equalf(t, tt.want, got, "statefulSetReady() = %v, want %v", got, tt.want) }) } } @@ -1014,19 +968,16 @@ func Test_ReadyChecker_podsReadyForObject(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) for _, pod := range tt.existPods { - if _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), &pod, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Pod error: %v", err) - return - } + _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), &pod, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Pod error") } got, err := c.podsReadyForObject(t.Context(), tt.args.namespace, tt.args.obj) - if (err != nil) != tt.wantErr { - t.Errorf("podsReadyForObject() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("podsReadyForObject() got = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "podsReadyForObject()") + } else { + require.NoError(t, err, "podsReadyForObject()") } + assert.Equal(t, tt.want, got, "podsReadyForObject() got = %v, want %v", got, tt.want) }) } } @@ -1097,9 +1048,7 @@ func Test_ReadyChecker_jobReady(t *testing.T) { t.Errorf("jobReady() error = %v, wantErr %v", err, tt.wantErr) return } - if got != tt.want { - t.Errorf("jobReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "jobReady() = %v, want %v", got, tt.want) }) } } @@ -1131,9 +1080,8 @@ func Test_ReadyChecker_volumeReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.volumeReady(tt.args.v); got != tt.want { - t.Errorf("volumeReady() = %v, want %v", got, tt.want) - } + got := c.volumeReady(tt.args.v) + assert.Equalf(t, tt.want, got, "volumeReady() = %v, want %v", got, tt.want) }) } } @@ -1177,9 +1125,7 @@ func Test_ReadyChecker_serviceReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.serviceReady(tt.args.service) - if got != tt.want { - t.Errorf("serviceReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "serviceReady() = %v, want %v", got, tt.want) }) } } @@ -1246,9 +1192,7 @@ func Test_ReadyChecker_crdBetaReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.crdBetaReady(tt.args.crdBeta) - if got != tt.want { - t.Errorf("crdBetaReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "crdBetaReady() = %v, want %v", got, tt.want) }) } } @@ -1315,9 +1259,7 @@ func Test_ReadyChecker_crdReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.crdReady(tt.args.crdBeta) - if got != tt.want { - t.Errorf("crdBetaReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "crdBetaReady() = %v, want %v", got, tt.want) }) } } From a3fa28ae22934450389ab31343c0ca20321d302c Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 104/161] chore(pkg): refactor: convert tests to testify assert/require part 12 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/action/install_test.go | 197 ++++++++++++------------------------ pkg/cmd/verify_test.go | 20 ++-- pkg/provenance/sign_test.go | 155 ++++++++-------------------- 3 files changed, 116 insertions(+), 256 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index f79590670..da680f41a 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -185,9 +185,7 @@ func TestInstallRelease(t *testing.T) { vals := map[string]any{} ctx, done := context.WithCancel(t.Context()) resi, err := instAction.RunWithContext(ctx, buildChart(), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Equal("test-install-release", res.Name, "Expected release name.") @@ -238,9 +236,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceNotOwned(t *testing.T) { instAction := installActionWithConfig(config) instAction.TakeOwnership = true resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -262,9 +258,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwned(t *testing.T) { instAction := installActionWithConfig(config) instAction.TakeOwnership = false resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) @@ -285,7 +279,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwnedNoFlag(t *testing.T) { instAction := installActionWithConfig(config) _, err := instAction.Run(buildChart(), nil) req.Error(err) - is.Contains(err.Error(), "unable to continue with install") + is.ErrorContains(err, "unable to continue with install") } func TestInstallReleaseWithValues(t *testing.T) { @@ -303,9 +297,7 @@ func TestInstallReleaseWithValues(t *testing.T) { }, } resi, err := instAction.Run(buildChart(withSampleValues()), userVals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Equal("test-install-release", res.Name, "Expected release name.") @@ -344,9 +336,7 @@ func TestInstallRelease_WithNotes(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("note here")), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -376,9 +366,7 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("got-{{.Release.Name}}")), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -400,9 +388,7 @@ func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -424,9 +410,7 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { instAction.SubNotes = true vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -451,9 +435,7 @@ func TestInstallRelease_DryRunClient(t *testing.T) { vals := map[string]any{} resi, err := instAction.Run(buildChart(withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -466,7 +448,7 @@ func TestInstallRelease_DryRunClient(t *testing.T) { _, err = instAction.cfg.Releases.Get(res.Name, res.Version) req.Error(err) is.Len(res.Hooks, 1) - is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "expect hook to not be marked as run") + is.Zero(res.Hooks[0].LastRun.CompletedAt, "expect hook to not be marked as run") is.Equal("Dry run complete", res.Info.Description) } } @@ -480,9 +462,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.DryRunStrategy = DryRunClient vals := map[string]any{} resi, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Contains(res.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret") @@ -495,9 +475,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.HideSecret = true vals = map[string]any{} res2i, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res2, err := releaserToV1Release(res2i) req.NoError(err) @@ -511,9 +489,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.DryRunStrategy = DryRunNone vals = map[string]any{} _, err = instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err == nil { - t.Fatal("Did not get the expected error when dry-run is false and hide secret is true") - } + req.Error(err, "Did not get the expected error when dry-run is false and hide secret is true") } // Regression test for #7955 @@ -532,9 +508,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { }) resi, err := instAction.Run(mockChart, vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -543,6 +517,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.DryRunStrategy = DryRunNone vals := map[string]any{} @@ -550,10 +525,8 @@ func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { expectedErr := `hello/templates/incorrect:1:10 executing "hello/templates/incorrect" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh` - if err == nil { - t.Fatalf("Install should fail containing error: %s", expectedErr) - } - is.Contains(err.Error(), expectedErr) + req.Error(err, "Install should fail containing error: %s", expectedErr) + is.ErrorContains(err, expectedErr) } func TestInstallRelease_NoHooks(t *testing.T) { @@ -562,17 +535,15 @@ func TestInstallRelease_NoHooks(t *testing.T) { instAction := installAction(t) instAction.DisableHooks = true instAction.ReleaseName = "no-hooks" - require.NoError(t, instAction.cfg.Releases.Create(releaseStub())) + req.NoError(instAction.cfg.Releases.Create(releaseStub())) vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) - is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "hooks should not run with no-hooks") + is.Zero(res.Hooks[0].LastRun.CompletedAt, "hooks should not run with no-hooks") } func TestInstallRelease_FailedHooks(t *testing.T) { @@ -637,7 +608,7 @@ func TestInstallRelease_KubeVersion(t *testing.T) { vals = map[string]any{} _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals) req.Error(err) - is.Contains(err.Error(), "chart requires kubeVersion: >=99.0.0 which is incompatible with Kubernetes v1.20.") + is.ErrorContains(err, "chart requires kubeVersion: >=99.0.0 which is incompatible with Kubernetes v1.20.") } func TestInstallRelease_Wait(t *testing.T) { @@ -680,7 +651,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { _, err := instAction.RunWithContext(ctx, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "context canceled") + req.ErrorContains(err, "context canceled") is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background time.Sleep(10 * time.Second) // wait for goroutine to finish @@ -723,8 +694,8 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { resi, err := instAction.Run(buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "I timed out") - is.Contains(err.Error(), "rollback-on-failure") + req.ErrorContains(err, "I timed out") + req.ErrorContains(err, "rollback-on-failure") res, err := releaserToV1Release(resi) req.NoError(err) @@ -748,9 +719,9 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { _, err := instAction.Run(buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "I timed out") - is.Contains(err.Error(), "uninstall fail") - is.Contains(err.Error(), "an error occurred while uninstalling the release") + req.ErrorContains(err, "I timed out") + req.ErrorContains(err, "uninstall fail") + is.ErrorContains(err, "an error occurred while uninstalling the release") }) } func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { @@ -771,9 +742,9 @@ func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { resi, err := instAction.RunWithContext(ctx, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "context canceled") - is.Contains(err.Error(), "rollback-on-failure") - is.Contains(err.Error(), "uninstalled") + req.ErrorContains(err, "context canceled") + req.ErrorContains(err, "rollback-on-failure") + req.ErrorContains(err, "uninstalled") res, err := releaserToV1Release(resi) req.NoError(err) @@ -820,36 +791,23 @@ func TestNameTemplate(t *testing.T) { } for _, tc := range testCases { - n, err := TemplateName(tc.tpl) - if err != nil { + t.Run(tc.tpl, func(t *testing.T) { + n, err := TemplateName(tc.tpl) if tc.expectedErrorStr == "" { - t.Errorf("Was not expecting error, but got: %v", err) - continue + require.NoError(t, err) + } else { + require.Error(t, err) + re, compErr := regexp.Compile(tc.expectedErrorStr) + require.NoError(t, compErr, "Expected error string failed to compile") + assert.True(t, re.MatchString(err.Error()), "Error didn't match for %s expected %s", tc.tpl, tc.expectedErrorStr) } - re, compErr := regexp.Compile(tc.expectedErrorStr) - if compErr != nil { - t.Errorf("Expected error string failed to compile: %v", compErr) - continue - } - if !re.MatchString(err.Error()) { - t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err) - continue - } - } - if err == nil && tc.expectedErrorStr != "" { - t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr) - } - if tc.expected != "" { - re, err := regexp.Compile(tc.expected) - if err != nil { - t.Errorf("Expected string failed to compile: %v", err) - continue - } - if !re.MatchString(n) { - t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n) + if tc.expected != "" { + re, err := regexp.Compile(tc.expected) + require.NoError(t, err) + assert.True(t, re.MatchString(n), "Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n) } - } + }) } } @@ -864,9 +822,7 @@ func TestInstallReleaseOutputDir(t *testing.T) { instAction.OutputDir = dir _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") _, err = os.Stat(filepath.Join(dir, "hello", "templates", "goodbye")) req.NoError(err) @@ -901,9 +857,7 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { newDir := filepath.Join(dir, instAction.ReleaseName) _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "goodbye")) req.NoError(err) @@ -925,46 +879,37 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { func TestNameAndChart(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) chartName := "./foo" name, chrt, err := instAction.NameAndChart([]string{chartName}) - if err != nil { - t.Fatal(err) - } + req.NoError(err) is.Equal(instAction.ReleaseName, name) is.Equal(chartName, chrt) instAction.GenerateName = true _, _, err = instAction.NameAndChart([]string{"foo", chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("cannot set --generate-name and also specify a name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "cannot set --generate-name and also specify a name") instAction.GenerateName = false instAction.NameTemplate = "{{ . }}" _, _, err = instAction.NameAndChart([]string{"foo", chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("cannot set --name-template and also specify a name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "cannot set --name-template and also specify a name") instAction.NameTemplate = "" instAction.ReleaseName = "" _, _, err = instAction.NameAndChart([]string{chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("must either provide a name or specify --generate-name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "must either provide a name or specify --generate-name") instAction.NameTemplate = "" instAction.ReleaseName = "" _, _, err = instAction.NameAndChart([]string{"foo", chartName, "bar"}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("expected at most two arguments, unexpected arguments: bar", err.Error()) + req.Error(err, "expected an error") + is.EqualError(err, "expected at most two arguments, unexpected arguments: bar") } func TestNameAndChartGenerateName(t *testing.T) { @@ -1016,9 +961,7 @@ func TestNameAndChartGenerateName(t *testing.T) { t.Parallel() name, chrt, err := instAction.NameAndChart([]string{tc.Chart}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) is.Equal(tc.ExpectedName, name) is.Equal(tc.Chart, chrt) @@ -1035,9 +978,7 @@ func TestInstallWithLabels(t *testing.T) { "key2": "val2", } resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -1046,17 +987,15 @@ func TestInstallWithLabels(t *testing.T) { func TestInstallWithSystemLabels(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.Labels = map[string]string{ "owner": "val1", "key2": "val2", } _, err := instAction.Run(buildChart(), nil) - if err == nil { - t.Fatal("expected an error") - } - - is.Equal(fmt.Errorf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) + req.Error(err, "expected an error") + is.EqualError(err, fmt.Sprintf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels())) } func TestUrlEqual(t *testing.T) { @@ -1111,13 +1050,9 @@ func TestUrlEqual(t *testing.T) { t.Parallel() u1, err := url.Parse(tc.url1) - if err != nil { - t.Fatalf("Failed to parse URL1 %s: %v", tc.url1, err) - } + require.NoError(t, err, "Failed to parse URL1 %s", tc.url1) u2, err := url.Parse(tc.url2) - if err != nil { - t.Fatalf("Failed to parse URL2 %s: %v", tc.url2, err) - } + require.NoError(t, err, "Failed to parse URL2 %s", tc.url2) is.Equal(tc.expected, urlEqual(u1, u2)) }) @@ -1285,11 +1220,7 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { instAction := installAction(t) - - err := instAction.installCRDs(tt.input) - if err == nil { - t.Error("got nil expected err") - } + assert.Error(t, instAction.installCRDs(tt.input), "got nil expected err") }) } } diff --git a/pkg/cmd/verify_test.go b/pkg/cmd/verify_test.go index 050d799c9..0b4078e1e 100644 --- a/pkg/cmd/verify_test.go +++ b/pkg/cmd/verify_test.go @@ -19,6 +19,9 @@ import ( "fmt" "runtime" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestVerifyCmd(t *testing.T) { @@ -73,18 +76,11 @@ func TestVerifyCmd(t *testing.T) { t.Run(tt.name, func(t *testing.T) { _, out, err := executeActionCommand(tt.cmd) if tt.wantError { - if err == nil { - t.Errorf("Expected error, but got none: %q", out) - } - if err.Error() != tt.expect { - t.Errorf("Expected error %q, got %q", tt.expect, err) - } - return - } else if err != nil { - t.Errorf("Unexpected error: %s", err) - } - if out != tt.expect { - t.Errorf("Expected %q, got %q", tt.expect, out) + require.Error(t, err, "Expected error, but got none: %q", out) + assert.EqualError(t, err, tt.expect, "Expected error %q", tt.expect) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expect, out, "Expected %q, got %q", tt.expect, out) } }) } diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 79b33a970..32253df90 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -89,14 +89,10 @@ func loadChartMetadataForSigning(t *testing.T, chartPath string) []byte { t.Helper() chart, err := loader.LoadFile(chartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) metadataBytes, err := yaml.Marshal(chart.Metadata) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return metadataBytes } @@ -106,170 +102,116 @@ func TestMessageBlock(t *testing.T) { // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) out, err := messageBlock(archiveData, filepath.Base(testChartfile), metadataBytes) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got := out.String() - if got != testMessageBlock { - t.Errorf("Expected:\n%q\nGot\n%q\n", testMessageBlock, got) - } + assert.Equal(t, testMessageBlock, got, "Expected:\n%q\nGot\n%q\n", testMessageBlock, got) } func TestParseMessageBlock(t *testing.T) { sc, err := parseMessageBlock([]byte(testMessageBlock)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // parseMessageBlock only returns checksums, not metadata (like upstream) - if lsc := len(sc.Files); lsc != 1 { - t.Errorf("Expected 1 file, got %d", lsc) - } + lsc := len(sc.Files) + assert.Equalf(t, 1, lsc, "Expected 1 file, got %d", lsc) - if hash, ok := sc.Files["hashtest-1.2.3.tgz"]; !ok { - t.Error("hashtest file not found in Files") - } else if hash != "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888" { - t.Errorf("Unexpected hash: %q", hash) - } + hash, ok := sc.Files["hashtest-1.2.3.tgz"] + assert.True(t, ok, "hashtest file not found in Files") + assert.Equalf(t, "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888", hash, "Unexpected hash: %q", hash) } func TestLoadKey(t *testing.T) { k, err := loadKey(testKeyfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := k.Identities[testKeyName]; !ok { - t.Errorf("Expected to load a key for user %q", testKeyName) - } + _, ok := k.Identities[testKeyName] + assert.Truef(t, ok, "Expected to load a key for user %q", testKeyName) } func TestLoadKeyRing(t *testing.T) { k, err := loadKeyRing(testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(k) > 1 { - t.Errorf("Expected 1, got %d", len(k)) - } + assert.LessOrEqualf(t, len(k), 1, "Expected 1, got %d", len(k)) for _, e := range k { - if ii, ok := e.Identities[testKeyName]; !ok { - t.Errorf("Expected %s in %v", testKeyName, ii) - } + ii, ok := e.Identities[testKeyName] + assert.Truef(t, ok, "Expected %s in %v", testKeyName, ii) } } func TestDigest(t *testing.T) { f, err := os.Open(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer f.Close() hash, err := Digest(f) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := readSumFile(testSumfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !strings.Contains(sig, hash) { - t.Errorf("Expected %s to be in %s", hash, sig) - } + assert.Contains(t, sig, hash, "Expected %s to be in %s", hash, sig) } func TestNewFromFiles(t *testing.T) { s, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := s.Entity.Identities[testKeyName]; !ok { - t.Errorf("Expected to load a key for user %q", testKeyName) - } + _, ok := s.Entity.Identities[testKeyName] + assert.Truef(t, ok, "Expected to load a key for user %q", testKeyName) } func TestDigestFile(t *testing.T) { hash, err := DigestFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := readSumFile(testSumfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !strings.Contains(sig, hash) { - t.Errorf("Expected %s to be in %s", hash, sig) - } + assert.Contains(t, sig, hash, "Expected %s to be in %s", hash, sig) } func TestDecryptKey(t *testing.T) { k, err := NewFromKeyring(testPasswordKeyfile, testPasswordKeyName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !k.Entity.PrivateKey.Encrypted { - t.Fatal("Key is not encrypted") - } + require.True(t, k.Entity.PrivateKey.Encrypted, "Key is not encrypted") // We give this a simple callback that returns the password. - if err := k.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, k.DecryptKey(func(_ string) ([]byte, error) { return []byte("secret"), nil - }); err != nil { - t.Fatal(err) - } + })) // Re-read the key (since we already unlocked it) k, err = NewFromKeyring(testPasswordKeyfile, testPasswordKeyName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Now we give it a bogus password. - if err := k.DecryptKey(func(_ string) ([]byte, error) { + require.Error(t, k.DecryptKey(func(_ string) ([]byte, error) { return []byte("secrets_and_lies"), nil - }); err == nil { - t.Fatal("Expected an error when giving a bogus passphrase") - } + }), "Expected an error when giving a bogus passphrase") } func TestClearSign(t *testing.T) { signer, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) metadataBytes := loadChartMetadataForSigning(t, testChartfile) // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) t.Logf("Sig:\n%s", sig) - if !strings.Contains(sig, testMessageBlock) { - t.Errorf("expected message block to be in sig: %s", sig) - } + assert.Contains(t, sig, testMessageBlock, "expected message block to be in sig: %s", sig) } func TestMixedKeyringRSASigningAndVerification(t *testing.T) { @@ -335,9 +277,7 @@ func (s failSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, er func TestClearSignError(t *testing.T) { signer, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // ensure that signing always fails signer.Entity.PrivateKey.PrivateKey = failSigner{} @@ -346,18 +286,11 @@ func TestClearSignError(t *testing.T) { // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes) - if err == nil { - t.Fatal("didn't get an error from ClearSign but expected one") - } - - if sig != "" { - t.Fatalf("expected an empty signature after failed ClearSign but got %q", sig) - } + require.Error(t, err, "didn't get an error from ClearSign but expected one") + assert.Empty(t, sig, "expected an empty signature after failed ClearSign but got %q", sig) } func TestVerify(t *testing.T) { @@ -386,7 +319,7 @@ func TestVerify(t *testing.T) { require.Errorf(t, err, "Expected %s to fail.", testTamperedSigBlock) var sErr pgperrors.SignatureError - if assert.ErrorAs(t, err, &sErr, "Expected invalid signature error, got %q (%T)", err, err) { + if assert.ErrorAs(t, err, &sErr, "Expected invalid signature error") { t.Logf("Tampered sig block error: %s (%T)", sErr, sErr) } } From aae82bf97a4c02c70982c14118912c459db43ec9 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 105/161] chore(pkg): refactor: convert tests to testify assert/require part 13 refactor: convert tests to testify assert/require in pkg Signed-off-by: Matthieu MOREL --- pkg/action/pull_test.go | 4 +- pkg/chart/v2/lint/rules/chartfile_test.go | 161 +++++----------------- pkg/cmd/search/search_test.go | 75 ++++------ pkg/pusher/ocipusher_test.go | 160 ++++++--------------- 4 files changed, 100 insertions(+), 300 deletions(-) diff --git a/pkg/action/pull_test.go b/pkg/action/pull_test.go index 7cd5d3e85..a483de248 100644 --- a/pkg/action/pull_test.go +++ b/pkg/action/pull_test.go @@ -48,9 +48,7 @@ func TestPullSetRegistryClient(t *testing.T) { func TestPullRun_ChartNotFound(t *testing.T) { srv, err := startLocalServerForTests(t, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() config := actionConfigFixture(t) diff --git a/pkg/chart/v2/lint/rules/chartfile_test.go b/pkg/chart/v2/lint/rules/chartfile_test.go index c9e202770..7c9f1c422 100644 --- a/pkg/chart/v2/lint/rules/chartfile_test.go +++ b/pkg/chart/v2/lint/rules/chartfile_test.go @@ -20,9 +20,11 @@ import ( "errors" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -47,35 +49,17 @@ var badChartName, _ = chartutil.LoadChartfile(badChartNamePath) func TestValidateChartYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingChartFilePath, os.ModePerm) defer os.Remove(nonExistingChartFilePath) - - err := validateChartYamlNotDirectory(nonExistingChartFilePath) - if err == nil { - t.Error("validateChartYamlNotDirectory to return a linter error, got no error") - } + assert.Error(t, validateChartYamlNotDirectory(nonExistingChartFilePath), "validateChartYamlNotDirectory to return a linter error, got no error") } func TestValidateChartYamlFormat(t *testing.T) { - err := validateChartYamlFormat(errors.New("Read error")) - if err == nil { - t.Error("validateChartYamlFormat to return a linter error, got no error") - } - - err = validateChartYamlFormat(nil) - if err != nil { - t.Error("validateChartYamlFormat to return no error, got a linter error") - } + require.Error(t, validateChartYamlFormat(errors.New("Read error")), "validateChartYamlFormat to return a linter error, got no error") + assert.NoError(t, validateChartYamlFormat(nil), "validateChartYamlFormat to return no error, got a linter error") } func TestValidateChartName(t *testing.T) { - err := validateChartName(badChart) - if err == nil { - t.Error("validateChartName to return a linter error, got no error") - } - - err = validateChartName(badChartName) - if err == nil { - t.Error("expected validateChartName to return a linter error for an invalid name, got no error") - } + require.Error(t, validateChartName(badChart), "validateChartName to return a linter error, got no error") + assert.Error(t, validateChartName(badChartName), "expected validateChartName to return a linter error for an invalid name, got no error") } func TestValidateChartVersion(t *testing.T) { @@ -93,18 +77,12 @@ func TestValidateChartVersion(t *testing.T) { for _, test := range failTest { badChart.Version = test.Version - err := validateChartVersion(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartVersion(badChart), test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) } for _, version := range successTest { badChart.Version = version - err := validateChartVersion(badChart) - if err != nil { - t.Errorf("validateChartVersion(%s) to return no error, got a linter error", version) - } + assert.NoError(t, validateChartVersion(badChart), "validateChartVersion(%s) to return no error, got a linter error", version) } } @@ -122,18 +100,12 @@ func TestValidateChartVersionStrictSemVerV2(t *testing.T) { for _, test := range failTest { badChart.Version = test.Version - err := validateChartVersionStrictSemVerV2(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartVersionStrictSemVerV2(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartVersionStrictSemVerV2(badChart), test.ErrorMsg, "validateChartVersionStrictSemVerV2(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) } for _, version := range successTest { badChart.Version = version - err := validateChartVersionStrictSemVerV2(badChart) - if err != nil { - t.Errorf("validateChartVersionStrictSemVerV2(%s) to return no error, got a linter error", version) - } + assert.NoError(t, validateChartVersionStrictSemVerV2(badChart), "validateChartVersionStrictSemVerV2(%s) to return no error, got a linter error", version) } } @@ -158,29 +130,17 @@ func TestValidateChartMaintainer(t *testing.T) { for _, test := range failTest { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartMaintainer(badChart), test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) } for _, test := range successTest { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err != nil { - t.Errorf("validateChartMaintainer(%s, %s) to return no error, got %s", test.Name, test.Email, err.Error()) - } + require.NoError(t, validateChartMaintainer(badChart), "validateChartMaintainer(%s, %s)", test.Name, test.Email) } // Testing for an empty maintainer badChart.Maintainers = []*chart.Maintainer{nil} - err := validateChartMaintainer(badChart) - if err == nil { - t.Error("validateChartMaintainer did not return error for nil maintainer as expected") - } - if err.Error() != "a maintainer entry is empty" { - t.Errorf("validateChartMaintainer returned unexpected error for nil maintainer: %s", err.Error()) - } + assert.EqualError(t, validateChartMaintainer(badChart), "a maintainer entry is empty") } func TestValidateChartSources(t *testing.T) { @@ -188,18 +148,12 @@ func TestValidateChartSources(t *testing.T) { var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} for _, test := range failTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid source URL") { - t.Errorf("validateChartSources(%s) to return \"invalid source URL\", got no error", test) - } + require.ErrorContainsf(t, validateChartSources(badChart), "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) } for _, test := range successTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartSources(%s) to return no error, got %s", test, err.Error()) - } + assert.NoError(t, validateChartSources(badChart), "validateChartSources(%s) to return no error", test) } } @@ -209,24 +163,13 @@ func TestValidateChartIconPresence(t *testing.T) { Icon: "", } - err := validateChartIconPresence(testChart) - - if err == nil { - t.Error("validateChartIconPresence to return a linter error, got no error") - } else if !strings.Contains(err.Error(), "icon is recommended") { - t.Errorf("expected %q, got %q", "icon is recommended", err.Error()) - } + assert.ErrorContainsf(t, validateChartIconPresence(testChart), "icon is recommended", "expected %q", "icon is recommended") }) t.Run("Icon present", func(t *testing.T) { testChart := &chart.Metadata{ Icon: "http://example.org/icon.png", } - - err := validateChartIconPresence(testChart) - - if err != nil { - t.Errorf("Unexpected error: %q", err.Error()) - } + assert.NoError(t, validateChartIconPresence(testChart)) }) } @@ -235,18 +178,12 @@ func TestValidateChartIconURL(t *testing.T) { var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} for _, test := range failTest { badChart.Icon = test - err := validateChartIconURL(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid icon URL") { - t.Errorf("validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) - } + require.ErrorContainsf(t, validateChartIconURL(badChart), "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) } for _, test := range successTest { badChart.Icon = test - err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartIconURL(%s) to return no error, got %s", test, err.Error()) - } + assert.NoError(t, validateChartSources(badChart), "validateChartIconURL(%s) to return no error", test) } } @@ -257,37 +194,15 @@ func TestChartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 7 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - - if !strings.Contains(msgs[0].Err.Error(), "name is required") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } - - if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } - - if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") { - t.Errorf("Unexpected message 4: %s", msgs[4].Err) - } + require.Lenf(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - if !strings.Contains(msgs[5].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { - t.Errorf("Unexpected message 5: %s", msgs[5].Err) - } - if !strings.Contains(msgs[6].Err.Error(), "version '0.0.0.0' is not a valid SemVerV2") { - t.Errorf("Unexpected message 6: %s", msgs[6].Err) - } + require.ErrorContains(t, msgs[0].Err, "name is required", "Unexpected message 0: %s", msgs[0].Err) + require.ErrorContains(t, msgs[1].Err, "apiVersion is required. The value must be either \"v1\" or \"v2\"", "Unexpected message 1: %s", msgs[1].Err) + require.ErrorContains(t, msgs[2].Err, "version '0.0.0.0' is not a valid SemVer", "Unexpected message 2: %s", msgs[2].Err) + require.ErrorContains(t, msgs[3].Err, "icon is recommended", "Unexpected message 3: %s", msgs[3].Err) + require.ErrorContains(t, msgs[4].Err, "chart type is not valid in apiVersion", "Unexpected message 4: %s", msgs[4].Err) + require.ErrorContains(t, msgs[5].Err, "dependencies are not valid in the Chart file with apiVersion", "Unexpected message 5: %s", msgs[5].Err) + assert.ErrorContains(t, msgs[6].Err, "version '0.0.0.0' is not a valid SemVerV2", "Unexpected message 6: %s", msgs[6].Err) }) t.Run("Chart.yaml validity issues due to type mismatch", func(t *testing.T) { @@ -301,19 +216,9 @@ func TestChartfile(t *testing.T) { return } - if !strings.Contains(msgs[0].Err.Error(), "version should be of type string") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "version '7.2445e+06' is not a valid SemVer") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "appVersion should be of type string") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } - if !strings.Contains(msgs[3].Err.Error(), "version '7.2445e+06' is not a valid SemVerV2") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } + require.ErrorContains(t, msgs[0].Err, "version should be of type string", "Unexpected message 0: %s", msgs[0].Err) + require.ErrorContains(t, msgs[1].Err, "version '7.2445e+06' is not a valid SemVer", "Unexpected message 1: %s", msgs[1].Err) + require.ErrorContains(t, msgs[2].Err, "appVersion should be of type string", "Unexpected message 2: %s", msgs[2].Err) + assert.ErrorContains(t, msgs[3].Err, "version '7.2445e+06' is not a valid SemVerV2", "Unexpected message 3: %s", msgs[3].Err) }) } diff --git a/pkg/cmd/search/search_test.go b/pkg/cmd/search/search_test.go index 46394e77f..f8c9504d1 100644 --- a/pkg/cmd/search/search_test.go +++ b/pkg/cmd/search/search_test.go @@ -20,6 +20,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/repo/v1" ) @@ -40,24 +43,16 @@ func TestSortScore(t *testing.T) { // Test Score for i := range expectScore { - if expectScore[i] != in[i].Score { - t.Errorf("Sort error on index %d: expected %d, got %d", i, expectScore[i], in[i].Score) - } + assert.Equalf(t, expectScore[i], in[i].Score, "Sort error on index %d: expected %d, got %d", i, expectScore[i], in[i].Score) } // Test Name for i := range expect { - if expect[i] != in[i].Name { - t.Errorf("Sort error: expected %s, got %s", expect[i], in[i].Name) - } + assert.Equalf(t, expect[i], in[i].Name, "Sort error: expected %s, got %s", expect[i], in[i].Name) } // Test version of last two items - if in[5].Chart.Version != "1.2.4" { - t.Errorf("Expected 1.2.4, got %s", in[5].Chart.Version) - } - if in[6].Chart.Version != "1.2.3" { - t.Error("Expected 1.2.3 to be last") - } + assert.Equalf(t, "1.2.4", in[5].Chart.Version, "Expected 1.2.4, got %s", in[5].Chart.Version) + assert.Equal(t, "1.2.3", in[6].Chart.Version, "Expected 1.2.3 to be last") } var indexfileEntries = map[string]repo.ChartVersions{ @@ -122,30 +117,22 @@ func loadTestIndex(_ *testing.T, all bool) *Index { func TestAll(t *testing.T) { i := loadTestIndex(t, false) all := i.All() - if len(all) != 4 { - t.Errorf("Expected 4 entries, got %d", len(all)) - } + assert.Lenf(t, all, 4, "Expected 4 entries, got %d", len(all)) i = loadTestIndex(t, true) all = i.All() - if len(all) != 5 { - t.Errorf("Expected 5 entries, got %d", len(all)) - } + assert.Lenf(t, all, 5, "Expected 5 entries, got %d", len(all)) } func TestAddRepo_Sort(t *testing.T) { i := loadTestIndex(t, true) sr, err := i.Search("TESTING/SANTA-MARIA", 100, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) SortScore(sr) ch := sr[0] expect := "1.2.3" - if ch.Chart.Version != expect { - t.Errorf("Expected %q, got %q", expect, ch.Chart.Version) - } + assert.Equalf(t, ch.Chart.Version, expect, "Expected %q, got %q", expect, ch.Chart.Version) } func TestSearchByName(t *testing.T) { @@ -247,9 +234,7 @@ func TestSearchByName(t *testing.T) { charts, err := i.Search(tt.query, 100, tt.regexp) if err != nil { if tt.fail { - if !strings.Contains(err.Error(), tt.failMsg) { - t.Fatalf("Unexpected error message: %s", err) - } + require.ErrorContains(t, err, tt.failMsg) return } t.Fatalf("%s: %s", tt.name, err) @@ -258,9 +243,7 @@ func TestSearchByName(t *testing.T) { SortScore(charts) l := len(charts) - if l != len(tt.expect) { - t.Fatalf("Expected %d result, got %d", len(tt.expect), l) - } + require.Lenf(t, tt.expect, l, "Expected %d result, got %d", len(tt.expect), l) // For empty result sets, just keep going. if l == 0 { return @@ -268,9 +251,7 @@ func TestSearchByName(t *testing.T) { for i, got := range charts { ex := tt.expect[i] - if got.Name != ex.Name { - t.Errorf("[%d]: Expected name %q, got %q", i, ex.Name, got.Name) - } + assert.Equalf(t, got.Name, ex.Name, "[%d]: Expected name %q, got %q", i, ex.Name, got.Name) } }) } @@ -280,12 +261,8 @@ func TestSearchByNameAll(t *testing.T) { // Test with the All bit turned on. i := loadTestIndex(t, true) cs, err := i.Search("santa-maria", 100, false) - if err != nil { - t.Fatal(err) - } - if len(cs) != 2 { - t.Errorf("expected 2 charts, got %d", len(cs)) - } + require.NoError(t, err) + assert.Lenf(t, cs, 2, "expected 2 charts, got %d", len(cs)) } func TestCalcScore(t *testing.T) { @@ -293,16 +270,12 @@ func TestCalcScore(t *testing.T) { fields := []string{"aaa", "bbb", "ccc", "ddd"} matchline := strings.Join(fields, sep) - if r := i.calcScore(2, matchline); r != 0 { - t.Errorf("Expected 0, got %d", r) - } - if r := i.calcScore(5, matchline); r != 1 { - t.Errorf("Expected 1, got %d", r) - } - if r := i.calcScore(10, matchline); r != 2 { - t.Errorf("Expected 2, got %d", r) - } - if r := i.calcScore(14, matchline); r != 3 { - t.Errorf("Expected 3, got %d", r) - } + r := i.calcScore(2, matchline) + assert.Equalf(t, 0, r, "Expected 0, got %d", r) + r = i.calcScore(5, matchline) + assert.Equalf(t, 1, r, "Expected 1, got %d", r) + r = i.calcScore(10, matchline) + assert.Equalf(t, 2, r, "Expected 2, got %d", r) + r = i.calcScore(14, matchline) + assert.Equalf(t, 3, r, "Expected 3, got %d", r) } diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index a4542500a..ceb61d442 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -21,9 +21,9 @@ import ( "io" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/registry" @@ -31,13 +31,10 @@ import ( func TestNewOCIPusher(t *testing.T) { p, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := p.(*OCIPusher); !ok { - t.Fatal("Expected NewOCIPusher to produce an *OCIPusher") - } + _, ok := p.(*OCIPusher) + require.True(t, ok, "Expected NewOCIPusher to produce an *OCIPusher") cd := "../../testdata" join := filepath.Join @@ -51,55 +48,28 @@ func TestNewOCIPusher(t *testing.T) { WithInsecureSkipTLSVerify(insecureSkipTLSVerify), WithPlainHTTP(plainHTTP), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) op, ok := p.(*OCIPusher) - if !ok { - t.Fatal("Expected NewOCIPusher to produce an *OCIPusher") - } - - if op.opts.certFile != pub { - t.Errorf("Expected NewOCIPusher to contain %q as the public key file, got %q", pub, op.opts.certFile) - } - - if op.opts.keyFile != priv { - t.Errorf("Expected NewOCIPusher to contain %q as the private key file, got %q", priv, op.opts.keyFile) - } - - if op.opts.caFile != ca { - t.Errorf("Expected NewOCIPusher to contain %q as the CA file, got %q", ca, op.opts.caFile) - } - - if op.opts.plainHTTP != plainHTTP { - t.Errorf("Expected NewOCIPusher to have plainHTTP as %t, got %t", plainHTTP, op.opts.plainHTTP) - } - - if op.opts.insecureSkipTLSVerify != insecureSkipTLSVerify { - t.Errorf("Expected NewOCIPusher to have insecureSkipVerifyTLS as %t, got %t", insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify) - } + require.True(t, ok, "Expected NewOCIPusher to produce an *OCIPusher") + assert.Equal(t, pub, op.opts.certFile, "Expected NewOCIPusher to contain %q as the public key file, got %q", pub, op.opts.certFile) + assert.Equal(t, priv, op.opts.keyFile, "Expected NewOCIPusher to contain %q as the private key file, got %q", priv, op.opts.keyFile) + assert.Equal(t, ca, op.opts.caFile, "Expected NewOCIPusher to contain %q as the CA file, got %q", ca, op.opts.caFile) + assert.Equal(t, plainHTTP, op.opts.plainHTTP, "Expected NewOCIPusher to have plainHTTP as %t, got %t", plainHTTP, op.opts.plainHTTP) + assert.Equal(t, insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify, "Expected NewOCIPusher to have insecureSkipVerifyTLS as %t, got %t", insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify) // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) p, err = NewOCIPusher( WithRegistryClient(registryClient), ) - if err != nil { - t.Fatal(err) - } - op, ok = p.(*OCIPusher) - if !ok { - t.Fatal("expected NewOCIPusher to produce an *OCIPusher") - } + require.NoError(t, err) - if op.opts.registryClient != registryClient { - t.Errorf("Expected NewOCIPusher to contain %p as RegistryClient, got %p", registryClient, op.opts.registryClient) - } + op, ok = p.(*OCIPusher) + require.True(t, ok, "expected NewOCIPusher to produce an *OCIPusher") + assert.Equal(t, registryClient, op.opts.registryClient, "Expected NewOCIPusher to contain %p as RegistryClient, got %p", registryClient, op.opts.registryClient) } func TestOCIPusher_Push_ErrorHandling(t *testing.T) { @@ -127,23 +97,13 @@ func TestOCIPusher_Push_ErrorHandling(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pusher, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) chartRef := tt.chartRef if tt.setupFunc != nil { chartRef = tt.setupFunc() } - - err = pusher.Push(chartRef, "oci://localhost:5000/test") - if err == nil { - t.Fatal("Expected error but got none") - } - - if !strings.Contains(err.Error(), tt.expectedError) { - t.Errorf("Expected error containing %q, got %q", tt.expectedError, err.Error()) - } + assert.ErrorContains(t, pusher.Push(chartRef, "oci://localhost:5000/test"), tt.expectedError) }) } } @@ -227,30 +187,20 @@ func TestOCIPusher_newRegistryClient(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pusher, err := NewOCIPusher(tt.opts...) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) op, ok := pusher.(*OCIPusher) - if !ok { - t.Fatal("Expected *OCIPusher") - } + require.True(t, ok, "Expected *OCIPusher") client, err := op.newRegistryClient() if tt.expectError { - if err == nil { - t.Fatal("Expected error but got none") - } - if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { - t.Errorf("Expected error containing %q, got %q", tt.errorContains, err.Error()) + require.Error(t, err, "Expected error but got none") + if tt.errorContains != "" { + require.ErrorContainsf(t, err, tt.errorContains, "Expected error containing %q, got %q", tt.errorContains, err.Error()) } } else { - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if client == nil { - t.Fatal("Expected non-nil registry client") - } + require.NoError(t, err) + require.NotNil(t, client, "Expected non-nil registry client") } }) } @@ -287,25 +237,18 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { // Copy a valid chart src, err := os.Open(chartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer src.Close() dst, err := os.Create(tempChart) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := io.Copy(dst, src); err != nil { - t.Fatal(err) - } + _, err = io.Copy(dst, src) + require.NoError(t, err) dst.Close() // Make the file unreadable - if err := os.Chmod(tempChart, 0o000); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Chmod(tempChart, 0o000)) return tempChart, func() { os.Chmod(tempChart, 0o644) // Restore permissions for cleanup @@ -328,25 +271,18 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { // Copy chart file src, err := os.Open(chartWithProvPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer src.Close() dst, err := os.Create(tempChart) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := io.Copy(dst, src); err != nil { - t.Fatal(err) - } + _, err = io.Copy(dst, src) + require.NoError(t, err) dst.Close() // Create provenance file - if err := os.WriteFile(tempProv, []byte("test provenance data"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tempProv, []byte("test provenance data"), 0o644)) return tempChart, func() {} }, @@ -373,9 +309,7 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { } pusher, err := NewOCIPusher(tt.options...) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = pusher.Push(chartRef, tt.href) @@ -400,27 +334,17 @@ func TestOCIPusher_Push_MultipleOptions(t *testing.T) { } pusher, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Test that multiple options are applied correctly - err = pusher.Push(chartPath, "oci://localhost:5000/test", + // We expect an error since we're not actually pushing to a registry + require.Error(t, pusher.Push(chartPath, "oci://localhost:5000/test", WithPlainHTTP(true), WithInsecureSkipTLSVerify(true), - ) - - // We expect an error since we're not actually pushing to a registry - if err == nil { - t.Fatal("Expected error when pushing without a valid registry") - } + ), "Expected error when pushing without a valid registry") // Verify options were applied op := pusher.(*OCIPusher) - if !op.opts.plainHTTP { - t.Error("Expected plainHTTP option to be applied") - } - if !op.opts.insecureSkipTLSVerify { - t.Error("Expected insecureSkipTLSVerify option to be applied") - } + assert.True(t, op.opts.plainHTTP, "Expected plainHTTP option to be applied") + assert.True(t, op.opts.insecureSkipTLSVerify, "Expected insecureSkipTLSVerify option to be applied") } From dc66ee7be786b1ac146a21fb2114b9678aaf25a4 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 106/161] chore(pkg): refactor: convert tests to testify assert/require part 14 refactor: convert tests to testify assert/require in pkg/storage/driver Signed-off-by: Matthieu MOREL --- pkg/chart/v2/metadata_test.go | 20 ++-- pkg/downloader/chart_downloader_test.go | 129 ++++++++---------------- pkg/storage/driver/secrets_test.go | 115 ++++++--------------- pkg/storage/driver/sql_test.go | 128 +++++++---------------- 4 files changed, 112 insertions(+), 280 deletions(-) diff --git a/pkg/chart/v2/metadata_test.go b/pkg/chart/v2/metadata_test.go index 63dd99e52..720ca4886 100644 --- a/pkg/chart/v2/metadata_test.go +++ b/pkg/chart/v2/metadata_test.go @@ -16,8 +16,10 @@ limitations under the License. package v2 import ( - "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { @@ -192,21 +194,13 @@ func TestValidate(t *testing.T) { for _, tt := range tests { result := tt.md.Validate() - if !errors.Is(result, tt.err) { - t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name) - } + assert.ErrorIs(t, result, tt.err, "expected %q, got %q in test %q", tt.err, result, tt.name) } } func TestValidate_sanitize(t *testing.T) { md := &Metadata{APIVersion: "v2", Name: "test", Version: "1.0", Description: "\adescr\u0081iption\rtest", Maintainers: []*Maintainer{{Name: "\r"}}} - if err := md.Validate(); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if md.Description != "description test" { - t.Fatalf("description was not sanitized: %q", md.Description) - } - if md.Maintainers[0].Name != " " { - t.Fatal("maintainer name was not sanitized") - } + require.NoError(t, md.Validate()) + require.Equal(t, "description test", md.Description, "description was not sanitized: %q", md.Description) + require.Equal(t, " ", md.Maintainers[0].Name, "maintainer name was not sanitized") } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index a4de2f5e3..7187bdff1 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -18,7 +18,6 @@ package downloader import ( "crypto/sha256" "encoding/hex" - "errors" "os" "path/filepath" "testing" @@ -69,9 +68,7 @@ func TestResolveChartRef(t *testing.T) { // Create a mock registry client for OCI references registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) c := ChartDownloader{ Out: os.Stderr, @@ -93,9 +90,8 @@ func TestResolveChartRef(t *testing.T) { t.Errorf("%s: failed with error %q", tt.name, err) continue } - if got := u.String(); got != tt.expect { - t.Errorf("%s: expected %s, got %s", tt.name, tt.expect, got) - } + got := u.String() + assert.Equalf(t, tt.expect, got, "%s: expected %s, got %s", tt.name, tt.expect, got) } } @@ -162,14 +158,10 @@ func TestResolveChartOpts(t *testing.T) { func TestVerifyChart(t *testing.T) { v, err := VerifyChart("testdata/signtest-0.1.0.tgz", "testdata/signtest-0.1.0.tgz.prov", "testdata/helm-test-key.pub") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // The verification is tested at length in the provenance package. Here, // we just want a quick sanity check that the v is not empty. - if v.FileHash == "" { - t.Error("Digest missing") - } + assert.NotEmpty(t, v.FileHash, "Digest missing") } func TestIsTar(t *testing.T) { @@ -183,9 +175,7 @@ func TestIsTar(t *testing.T) { } for src, expect := range tests { - if isTar(src) != expect { - t.Errorf("%q should be %t", src, expect) - } + assert.Equal(t, expect, isTar(src), "%q should be %t", src, expect) } } @@ -196,13 +186,8 @@ func TestDownloadTo(t *testing.T) { repotest.WithMiddleware(repotest.BasicAuthMiddleware(t)), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) contentCache := t.TempDir() @@ -226,21 +211,14 @@ func TestDownloadTo(t *testing.T) { cname := "/signtest-0.1.0.tgz" dest := srv.Root() where, v, err := c.DownloadTo(srv.URL()+cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if expect := filepath.Join(dest, cname); where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } - - if v.FileHash == "" { - t.Error("File hash was empty, but verification is required.") - } + expect := filepath.Join(dest, cname) + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) + assert.NotEmpty(t, v.FileHash, "File hash was empty, but verification is required.") - if _, err := os.Stat(filepath.Join(dest, cname)); err != nil { - t.Error(err) - } + _, err = os.Stat(filepath.Join(dest, cname)) + assert.NoError(t, err) } func TestDownloadTo_TLS(t *testing.T) { @@ -251,12 +229,8 @@ func TestDownloadTo_TLS(t *testing.T) { repotest.WithTLSConfig(repotest.MakeTestTLSConfig(t, "../../testdata")), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) repoConfig := filepath.Join(srv.Root(), "repositories.yaml") repoCache := srv.Root() @@ -285,22 +259,15 @@ func TestDownloadTo_TLS(t *testing.T) { cname := "test/signtest" dest := srv.Root() where, v, err := c.DownloadTo(cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) target := filepath.Join(dest, "signtest-0.1.0.tgz") - if expect := target; where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } + expect := target + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) + assert.NotEmpty(t, v.FileHash, "File hash was empty, but verification is required.") - if v.FileHash == "" { - t.Error("File hash was empty, but verification is required.") - } - - if _, err := os.Stat(target); err != nil { - t.Error(err) - } + _, err = os.Stat(target) + assert.NoError(t, err) } func TestDownloadTo_VerifyLater(t *testing.T) { @@ -314,9 +281,7 @@ func TestDownloadTo_VerifyLater(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) contentCache := t.TempDir() c := ChartDownloader{ @@ -333,20 +298,16 @@ func TestDownloadTo_VerifyLater(t *testing.T) { } cname := "/signtest-0.1.0.tgz" where, _, err := c.DownloadTo(srv.URL()+cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if expect := filepath.Join(dest, cname); where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } + expect := filepath.Join(dest, cname) + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) - if _, err := os.Stat(filepath.Join(dest, cname)); err != nil { - t.Fatal(err) - } - if _, err := os.Stat(filepath.Join(dest, cname+".prov")); err != nil { - t.Fatal(err) - } + _, err = os.Stat(filepath.Join(dest, cname)) + require.NoError(t, err) + + _, err = os.Stat(filepath.Join(dest, cname+".prov")) + require.NoError(t, err) } func TestScanReposForURL(t *testing.T) { @@ -363,24 +324,17 @@ func TestScanReposForURL(t *testing.T) { u := "http://example.com/alpine-0.2.0.tgz" rf, err := repo.LoadFile(repoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) entry, err := c.scanReposForURL(u, rf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if entry.Name != "testing" { - t.Errorf("Unexpected repo %q for URL %q", entry.Name, u) - } + assert.Equal(t, "testing", entry.Name, "Unexpected repo %q for URL %q", entry.Name, u) // A lookup failure should produce an ErrNoOwnerRepo u = "https://no.such.repo/foo/bar-1.23.4.tgz" - if _, err = c.scanReposForURL(u, rf); !errors.Is(err, ErrNoOwnerRepo) { - t.Fatalf("expected ErrNoOwnerRepo, got %v", err) - } + _, err = c.scanReposForURL(u, rf) + require.ErrorIs(t, err, ErrNoOwnerRepo) } func TestDownloadToCache(t *testing.T) { @@ -388,12 +342,8 @@ func TestDownloadToCache(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) // The repo file needs to point to our server. repoFile := filepath.Join(srv.Root(), "repositories.yaml") @@ -431,6 +381,7 @@ func TestDownloadToCache(t *testing.T) { // Check that it's in the cache digest, _, err := c.ResolveChartVersion("test/signtest", "0.1.0") require.NoError(t, err) + digestBytes, err := hex.DecodeString(digest) require.NoError(t, err) var digestArray [sha256.Size]byte @@ -472,6 +423,7 @@ func TestDownloadToCache(t *testing.T) { // Check that both chart and prov are in cache digest, _, err := c.ResolveChartVersion("test/signtest", "0.1.0") require.NoError(t, err) + digestBytes, err := hex.DecodeString(digest) require.NoError(t, err) var digestArray [sha256.Size]byte @@ -479,6 +431,7 @@ func TestDownloadToCache(t *testing.T) { _, err = c.Cache.Get(digestArray, CacheChart) require.NoError(t, err, "chart should be in cache") + _, err = c.Cache.Get(digestArray, CacheProv) require.NoError(t, err, "provenance file should be in cache") diff --git a/pkg/storage/driver/secrets_test.go b/pkg/storage/driver/secrets_test.go index a11ec4380..8cc3f390d 100644 --- a/pkg/storage/driver/secrets_test.go +++ b/pkg/storage/driver/secrets_test.go @@ -16,10 +16,11 @@ package driver import ( "encoding/base64" "encoding/json" - "errors" "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "helm.sh/helm/v4/pkg/release" @@ -29,9 +30,7 @@ import ( func TestSecretName(t *testing.T) { c := newTestFixtureSecrets(t) - if c.Name() != SecretsDriverName { - t.Errorf("Expected name to be %q, got %q", SecretsDriverName, c.Name()) - } + assert.Equal(t, SecretsDriverName, c.Name(), "Expected name to be %q, got %q", SecretsDriverName, c.Name()) } func TestSecretGet(t *testing.T) { @@ -45,13 +44,9 @@ func TestSecretGet(t *testing.T) { // get release with key got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func TestUNcompressedSecretGet(t *testing.T) { @@ -63,13 +58,9 @@ func TestUNcompressedSecretGet(t *testing.T) { // Create a test fixture which contains an uncompressed release secret, err := newSecretsObject(key, rel, nil) - if err != nil { - t.Fatalf("Failed to create secret: %s", err) - } + require.NoError(t, err, "Failed to create secret") b, err := json.Marshal(rel) - if err != nil { - t.Fatalf("Failed to marshal release: %s", err) - } + require.NoError(t, err, "Failed to marshal release") secret.Data["release"] = []byte(base64.StdEncoding.EncodeToString(b)) var mock MockSecretsInterface mock.objects = map[string]*v1.Secret{key: secret} @@ -77,13 +68,9 @@ func TestUNcompressedSecretGet(t *testing.T) { // get release with key got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func TestSecretList(t *testing.T) { @@ -102,12 +89,8 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %s", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) // list all deployed releases dpl, err := secrets.List(func(rel release.Releaser) bool { @@ -115,12 +98,8 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) // list all superseded releases ssd, err := secrets.List(func(rel release.Releaser) bool { @@ -128,22 +107,14 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %s", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded") + assert.Len(t, ssd, 2, "Expected 2 superseded, got %d", len(ssd)) // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSecretQuery(t *testing.T) { @@ -157,17 +128,11 @@ func TestSecretQuery(t *testing.T) { }...) rls, err := secrets.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Fatalf("Failed to query: %s", err) - } - if len(rls) != 2 { - t.Fatalf("Expected 2 results, actual %d", len(rls)) - } + require.NoError(t, err, "Failed to query") + require.Len(t, rls, 2, "Expected 2 results, actual %d", len(rls)) _, err = secrets.Query(map[string]string{"name": "notExist"}) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } func TestSecretCreate(t *testing.T) { @@ -180,20 +145,14 @@ func TestSecretCreate(t *testing.T) { rel := releaseStub(name, vers, namespace, common.StatusDeployed) // store the release in a secret - if err := secrets.Create(key, rel); err != nil { - t.Fatalf("Failed to create release with key %q: %s", key, err) - } + require.NoErrorf(t, secrets.Create(key, rel), "Failed to create release with key %q", key) // get the release back got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) } func TestSecretUpdate(t *testing.T) { @@ -209,21 +168,15 @@ func TestSecretUpdate(t *testing.T) { rel.Info.Status = common.StatusSuperseded // perform the update - if err := secrets.Update(key, rel); err != nil { - t.Fatalf("Failed to update release: %s", err) - } + require.NoErrorf(t, secrets.Update(key, rel), "Failed to update release") // fetch the updated release goti, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) got := convertReleaserToV1(t, goti) // check release has actually been updated by comparing modified fields - if rel.Info.Status != got.Info.Status { - t.Errorf("Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) - } + assert.Equal(t, got.Info.Status, rel.Info.Status, "Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) } func TestSecretDelete(t *testing.T) { @@ -237,20 +190,12 @@ func TestSecretDelete(t *testing.T) { // perform the delete on a non-existing release _, err := secrets.Delete("nonexistent") - if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("Expected ErrReleaseNotFound, got: {%v}", err) - } + require.ErrorIs(t, err, ErrReleaseNotFound, "Expected ErrReleaseNotFound") // perform the delete rls, err := secrets.Delete(key) - if err != nil { - t.Fatalf("Failed to delete release with key %q: %s", key, err) - } - if !reflect.DeepEqual(rel, rls) { - t.Errorf("Expected {%v}, got {%v}", rel, rls) - } + require.NoError(t, err, "Failed to delete release with key %q", key) + assert.Truef(t, reflect.DeepEqual(rel, rls), "Expected {%v}, got {%v}", rel, rls) _, err = secrets.Get(key) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index 6044ce3c6..adcc780aa 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -24,6 +24,8 @@ import ( sqlmock "github.com/DATA-DOG/go-sqlmock" migrate "github.com/rubenv/sql-migrate" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" "helm.sh/helm/v4/pkg/release/common" @@ -59,9 +61,7 @@ func (recentUnixTimestampArgument) Match(value driver.Value) bool { func TestSQLName(t *testing.T) { sqlDriver, _ := newTestFixtureSQL(t) - if sqlDriver.Name() != SQLDriverName { - t.Errorf("Expected name to be %s, got %s", SQLDriverName, sqlDriver.Name()) - } + assert.Equal(t, SQLDriverName, sqlDriver.Name(), "Expected name to be %s, got %s", SQLDriverName, sqlDriver.Name()) } func TestSQLGet(t *testing.T) { @@ -97,17 +97,10 @@ func TestSQLGet(t *testing.T) { mockGetReleaseCustomLabels(mock, key, namespace, rel.Labels) got, err := sqlDriver.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %v", err) - } + require.NoError(t, err, "Failed to get release") - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected release {%v}, got {%v}", rel, got) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + assert.Truef(t, reflect.DeepEqual(rel, got), "Expected release {%v}, got {%v}", rel, got) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSQLList(t *testing.T) { @@ -157,12 +150,8 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %v", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) // list all deployed releases dpl, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -170,12 +159,8 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %v", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d:\n%v\n", len(dpl), dpl) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed, got %d:\n%v\n", len(dpl), dpl) // list all superseded releases ssd, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -183,27 +168,16 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %v", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoError(t, err, "Failed to list superseded") + assert.Len(t, ssd, 2, "Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd) + require.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSqlCreate(t *testing.T) { @@ -254,13 +228,8 @@ func TestSqlCreate(t *testing.T) { } mock.ExpectCommit() - if err := sqlDriver.Create(key, rel); err != nil { - t.Fatalf("failed to create release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoErrorf(t, sqlDriver.Create(key, rel), "failed to create release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlCreateAlreadyExists(t *testing.T) { @@ -315,13 +284,8 @@ func TestSqlCreateAlreadyExists(t *testing.T) { ).RowsWillBeClosed() mock.ExpectRollback() - if err := sqlDriver.Create(key, rel); err == nil { - t.Fatalf("failed to create release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.Errorf(t, sqlDriver.Create(key, rel), "failed to create release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlUpdate(t *testing.T) { @@ -352,13 +316,8 @@ func TestSqlUpdate(t *testing.T) { WithArgs(body, rel.Name, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, recentUnixTimestamp(), key, namespace). WillReturnResult(sqlmock.NewResult(0, 1)) - if err := sqlDriver.Update(key, rel); err != nil { - t.Fatalf("failed to update release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoErrorf(t, sqlDriver.Update(key, rel), "failed to update release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlQuery(t *testing.T) { @@ -448,31 +407,20 @@ func TestSqlQuery(t *testing.T) { mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels) _, err := sqlDriver.Query(labelSetUnknown) - if err == nil { - t.Errorf("Expected error {%v}, got nil", ErrReleaseNotFound) - } else if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("failed to query for unknown smug-pigeon release: %v", err) - } + require.Errorf(t, err, "Expected error {%v}, got nil", ErrReleaseNotFound) + require.ErrorIsf(t, err, ErrReleaseNotFound, "failed to query for unknown smug-pigeon release") results, err := sqlDriver.Query(labelSetDeployed) - if err != nil { - t.Fatalf("failed to query for deployed smug-pigeon release: %v", err) - } + require.NoError(t, err, "failed to query for deployed smug-pigeon release") for _, res := range results { - if !reflect.DeepEqual(res, deployedRelease) { - t.Errorf("Expected release {%v}, got {%v}", deployedRelease, res) - } + assert.Truef(t, reflect.DeepEqual(res, deployedRelease), "Expected release {%v}, got {%v}", deployedRelease, res) } results, err = sqlDriver.Query(labelSetAll) - if err != nil { - t.Fatalf("failed to query release history for smug-pigeon: %v", err) - } + require.NoError(t, err, "failed to query release history for smug-pigeon") - if len(results) != 2 { - t.Errorf("expected a resultset of size 2, got %d", len(results)) - } + assert.Len(t, results, 2, "expected a resultset of size 2, got %d", len(results)) for _, res := range results { if !reflect.DeepEqual(res, deployedRelease) && !reflect.DeepEqual(res, supersededRelease) { @@ -480,9 +428,7 @@ func TestSqlQuery(t *testing.T) { } } - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlDelete(t *testing.T) { @@ -544,16 +490,12 @@ func TestSqlDelete(t *testing.T) { mock.ExpectCommit() deletedRelease, err := sqlDriver.Delete(key) - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } - if err != nil { - t.Fatalf("failed to delete release with key %q: %v", key, err) - } + require.NoError(t, err) + err = mock.ExpectationsWereMet() + assert.NoErrorf(t, err, "sql expectations weren't met") + require.NoError(t, err, "failed to delete release with key %q", key) - if !reflect.DeepEqual(rel, deletedRelease) { - t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease) - } + assert.Truef(t, reflect.DeepEqual(rel, deletedRelease), "Expected release {%v}, got {%v}", rel, deletedRelease) } func mockGetReleaseCustomLabels(mock sqlmock.Sqlmock, key string, namespace string, labels map[string]string) { @@ -621,8 +563,6 @@ func TestSqlCheckAppliedMigrations(t *testing.T) { ExpectQuery(""). WillReturnRows(rows) mock.ExpectCommit() - if sqlDriver.checkAlreadyApplied(c.migrationsToApply) != c.expectedResult { - t.Errorf("Test case: %v, Expected: %v, Have: %v, Explanation: %v", i, c.expectedResult, !c.expectedResult, c.errorExplanation) - } + assert.Equal(t, c.expectedResult, sqlDriver.checkAlreadyApplied(c.migrationsToApply), "Test case: %v, Expected: %v, Have: %v, Explanation: %v", i, c.expectedResult, !c.expectedResult, c.errorExplanation) } } From 71733656a5c64307f85290bc9fe6480ad637a117 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 107/161] chore(pkg): refactor: convert tests to testify assert/require part 15 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/chart/loader/load_test.go | 66 +++++++----------- pkg/cmd/dependency_update_test.go | 106 +++++++++------------------- pkg/cmd/repo_index_test.go | 112 +++++++++--------------------- pkg/getter/ocigetter_test.go | 92 +++++++----------------- 4 files changed, 116 insertions(+), 260 deletions(-) diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index a42861eac..3834fad7a 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -24,10 +24,12 @@ import ( "io" "maps" "path/filepath" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + c3 "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/pkg/chart" c2 "helm.sh/helm/v4/pkg/chart/v2" @@ -59,20 +61,13 @@ description: A test chart Size: int64(len(data)), ModTime: time.Now(), } - if err := tw.WriteHeader(header); err != nil { - t.Fatalf("Failed to write tar header for %s: %v", name, err) - } - if _, err := tw.Write(data); err != nil { - t.Fatalf("Failed to write tar data for %s: %v", name, err) - } + require.NoErrorf(t, tw.WriteHeader(header), "Failed to write tar header for %s", name) + _, err := tw.Write(data) + require.NoErrorf(t, err, "Failed to write tar data for %s", name) } - if err := tw.Close(); err != nil { - t.Fatalf("Failed to close tar writer: %v", err) - } - if err := gw.Close(); err != nil { - t.Fatalf("Failed to close gzip writer: %v", err) - } + require.NoErrorf(t, tw.Close(), "Failed to close tar writer") + require.NoErrorf(t, gw.Close(), "Failed to close gzip writer") return &buf } @@ -149,37 +144,26 @@ func TestLoadArchive(t *testing.T) { loadedChart, err := LoadArchive(reader) if tc.expectedError != "" { - if err == nil || !strings.Contains(err.Error(), tc.expectedError) { - t.Errorf("Expected error containing %q, but got %v", tc.expectedError, err) - } - return - } + require.Errorf(t, err, "Expected error containing %q, but got no error", tc.expectedError) + assert.ErrorContains(t, err, tc.expectedError) + } else { + require.NoError(t, err) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - lac, err := chart.NewAccessor(loadedChart) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - eac, err := chart.NewAccessor(tc.expectedChart) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + lac, err := chart.NewAccessor(loadedChart) + require.NoError(t, err) - if lac.Name() != eac.Name() { - t.Errorf("Expected chart name %q, got %q", eac.Name(), lac.Name()) - } + eac, err := chart.NewAccessor(tc.expectedChart) + require.NoError(t, err) + assert.Equalf(t, lac.Name(), eac.Name(), "Expected chart name %q, got %q", eac.Name(), lac.Name()) - var loadedAPIVersion string - switch lc := loadedChart.(type) { - case *c2.Chart: - loadedAPIVersion = lc.Metadata.APIVersion - case *c3.Chart: - loadedAPIVersion = lc.Metadata.APIVersion - } - if loadedAPIVersion != tc.apiVersion { - t.Errorf("Expected API version %q, got %q", tc.apiVersion, loadedAPIVersion) + var loadedAPIVersion string + switch lc := loadedChart.(type) { + case *c2.Chart: + loadedAPIVersion = lc.Metadata.APIVersion + case *c3.Chart: + loadedAPIVersion = lc.Metadata.APIVersion + } + assert.Equalf(t, loadedAPIVersion, tc.apiVersion, "Expected API version %q, got %q", tc.apiVersion, loadedAPIVersion) } }) } diff --git a/pkg/cmd/dependency_update_test.go b/pkg/cmd/dependency_update_test.go index f9ff68097..13eb74532 100644 --- a/pkg/cmd/dependency_update_test.go +++ b/pkg/cmd/dependency_update_test.go @@ -16,14 +16,15 @@ limitations under the License. package cmd import ( - "errors" "fmt" "io/fs" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" chart "helm.sh/helm/v4/pkg/chart/v2" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -42,21 +43,16 @@ func TestDependencyUpdateCmd(t *testing.T) { t.Logf("Listening on directory %s", srv.Root()) ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) contentCache := t.TempDir() ociChartName := "oci-depending-chart" c := createTestingMetadataForOCI(ociChartName, ociSrv.RegistryURL) - if _, err := chartutil.Save(c, ociSrv.Dir); err != nil { - t.Fatal(err) - } + _, err = chartutil.Save(c, ociSrv.Dir) + require.NoError(t, err) ociSrv.Run(t, repotest.WithDependingChart(c)) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) @@ -65,9 +61,7 @@ func TestDependencyUpdateCmd(t *testing.T) { chartname := "depup" ch := createTestingMetadata(chartname, srv.URL()) md := ch.Metadata - if err := chartutil.SaveDir(ch, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(ch, dir())) _, out, err := executeActionCommand( fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --content-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir(), contentCache), @@ -78,30 +72,22 @@ func TestDependencyUpdateCmd(t *testing.T) { } // This is written directly to stdout, so we have to capture as is. - if !strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did not get updated\n%s", out) - } + assert.Contains(t, out, `update from the "test" chart repository`, "Repo did not get updated\n%s", out) // Make sure the actual file got downloaded. expect := dir(chartname, "charts/reqtest-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) hash, err := provenance.DigestFile(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) i, err := repo.LoadIndexFile(dir(helmpath.CacheIndexFile("test"))) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) reqver := i.Entries["reqtest"][0] - if h := reqver.Digest; h != hash { - t.Errorf("Failed hash match: expected %s, got %s", hash, h) - } + h := reqver.Digest + assert.Equalf(t, h, hash, "Failed hash match: expected %s, got %s", hash, h) // Now change the dependencies and update. This verifies that on update, // old dependencies are cleansed and new dependencies are added. @@ -109,9 +95,7 @@ func TestDependencyUpdateCmd(t *testing.T) { {Name: "reqtest", Version: "0.1.0", Repository: srv.URL()}, {Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()}, } - if err := chartutil.SaveChartfile(dir(chartname, "Chart.yaml"), md); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveChartfile(dir(chartname, "Chart.yaml"), md)) _, out, err = executeActionCommand(fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --content-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir(), contentCache)) if err != nil { @@ -122,18 +106,14 @@ func TestDependencyUpdateCmd(t *testing.T) { // In this second run, we should see compressedchart-0.3.0.tgz, and not // the 0.1.0 version. expect = dir(chartname, "charts/compressedchart-0.3.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatalf("Expected %q: %s", expect, err) - } + _, err = os.Stat(expect) + require.NoErrorf(t, err, "Expected %q", expect) unexpected := dir(chartname, "charts/compressedchart-0.1.0.tgz") - if _, err := os.Stat(unexpected); err == nil { - t.Fatalf("Unexpected %q", unexpected) - } + _, err = os.Stat(unexpected) + require.Errorf(t, err, "Unexpected %q", unexpected) // test for OCI charts - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) cmd := fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --content-cache %s --plain-http", dir(ociChartName), dir("repositories.yaml"), @@ -146,9 +126,8 @@ func TestDependencyUpdateCmd(t *testing.T) { t.Fatal(err) } expect = dir(ociChartName, "charts/oci-dependent-chart-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) } func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { @@ -162,9 +141,7 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { defer srv.Stop() t.Logf("Listening on directory %s", srv.Root()) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) chartname := "depupdelete" @@ -191,25 +168,18 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { // Make sure charts dir still has dependencies files, err := os.ReadDir(filepath.Join(dir(chartname), "charts")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dependencies := []string{"compressedchart-0.1.0.tgz", "reqtest-0.1.0.tgz"} - if len(dependencies) != len(files) { - t.Fatalf("Expected %d chart dependencies, got %d", len(dependencies), len(files)) - } + require.Len(t, dependencies, len(files), "Expected %d chart dependencies, got %d", len(dependencies), len(files)) for index, file := range files { - if dependencies[index] != file.Name() { - t.Fatalf("Chart dependency %s not matching %s", dependencies[index], file.Name()) - } + require.Equal(t, file.Name(), dependencies[index], "Chart dependency %s not matching %s", dependencies[index], file.Name()) } // Make sure tmpcharts-x is deleted tmpPath := filepath.Join(dir(chartname), fmt.Sprintf("tmpcharts-%d", os.Getpid())) - if _, err := os.Stat(tmpPath); !errors.Is(err, fs.ErrNotExist) { - t.Fatal("tmpcharts dir still exists") - } + _, err = os.Stat(tmpPath) + require.ErrorIs(t, err, fs.ErrNotExist, "tmpcharts dir still exists") } func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { @@ -231,9 +201,7 @@ func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { } ch.Metadata.Dependencies = append(ch.Metadata.Dependencies, chartDependency) - if err := chartutil.SaveDir(ch, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(ch, dir())) contentCache := t.TempDir() @@ -248,10 +216,8 @@ func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { } // This is written directly to stdout, so we have to capture as is - if !strings.Contains(out, `Getting updates for unmanaged Helm repositories...`) { - t.Errorf("No ‘unmanaged’ Helm repo used in test chartdependency or it doesn’t cause the creation "+ - "of an ‘ad hoc’ repo index cache file\n%s", out) - } + assert.Contains(t, out, `Getting updates for unmanaged Helm repositories...`, "No ‘unmanaged’ Helm repo used in test chartdependency or it doesn’t cause the creation "+ + "of an ‘ad hoc’ repo index cache file\n%s", out) } func setupMockRepoServer(t *testing.T) *repotest.Server { @@ -263,9 +229,7 @@ func setupMockRepoServer(t *testing.T) *repotest.Server { t.Logf("Listening on directory %s", srv.Root()) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) return srv } @@ -306,7 +270,5 @@ func createTestingMetadataForOCI(name, registryURL string) *chart.Chart { func createTestingChart(t *testing.T, dest, name, baseURL string) { t.Helper() cfile := createTestingMetadata(name, baseURL) - if err := chartutil.SaveDir(cfile, dest); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(cfile, dest)) } diff --git a/pkg/cmd/repo_index_test.go b/pkg/cmd/repo_index_test.go index 68f105d6d..30700749b 100644 --- a/pkg/cmd/repo_index_test.go +++ b/pkg/cmd/repo_index_test.go @@ -24,6 +24,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1" ) @@ -31,134 +34,81 @@ func TestRepoIndexCmd(t *testing.T) { dir := t.TempDir() comp := filepath.Join(dir, "compressedchart-0.1.0.tgz") - if err := linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp)) comp2 := filepath.Join(dir, "compressedchart-0.2.0.tgz") - if err := linkOrCopy("testdata/testcharts/compressedchart-0.2.0.tgz", comp2); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.2.0.tgz", comp2)) buf := bytes.NewBuffer(nil) c := newRepoIndexCmd(buf) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) destIndex := filepath.Join(dir, "index.yaml") index, err := repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(index.Entries) != 1 { - t.Errorf("expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) - } + assert.Len(t, index.Entries, 1, "expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) vs := index.Entries["compressedchart"] - if len(vs) != 2 { - t.Errorf("expected 2 versions, got %d: %#v", len(vs), vs) - } + assert.Len(t, vs, 2, "expected 2 versions, got %d: %#v", len(vs), vs) expectedVersion := "0.2.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) b, err := os.ReadFile(destIndex) - if err != nil { - t.Fatal(err) - } - if json.Valid(b) { - t.Error("did not expect index file to be valid json") - } + require.NoError(t, err) + assert.False(t, json.Valid(b), "did not expect index file to be valid json") // Test with `--json` c.ParseFlags([]string{"--json", "true"}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) - if b, err = os.ReadFile(destIndex); err != nil { - t.Fatal(err) - } - if !json.Valid(b) { - t.Error("index file is not valid json") - } + b, err = os.ReadFile(destIndex) + require.NoError(t, err) + assert.True(t, json.Valid(b), "index file is not valid json") // Test with `--merge` // Remove first two charts. - if err := os.Remove(comp); err != nil { - t.Fatal(err) - } - if err := os.Remove(comp2); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(comp)) + require.NoError(t, os.Remove(comp2)) // Add a new chart and a new version of an existing chart - if err := linkOrCopy("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz")); err != nil { - t.Fatal(err) - } - if err := linkOrCopy("testdata/testcharts/compressedchart-0.3.0.tgz", filepath.Join(dir, "compressedchart-0.3.0.tgz")); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz"))) + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.3.0.tgz", filepath.Join(dir, "compressedchart-0.3.0.tgz"))) c.ParseFlags([]string{"--merge", destIndex}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) index, err = repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(index.Entries) != 2 { - t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) - } + assert.Len(t, index.Entries, 2, "expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) vs = index.Entries["compressedchart"] - if len(vs) != 3 { - t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs) - } + assert.Len(t, vs, 3, "expected 3 versions, got %d: %#v", len(vs), vs) expectedVersion = "0.3.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) // test that index.yaml gets generated on merge even when it doesn't exist - if err := os.Remove(destIndex); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(destIndex)) c.ParseFlags([]string{"--merge", destIndex}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) index, err = repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // verify it didn't create an empty index.yaml and the merged happened - if len(index.Entries) != 2 { - t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) - } + assert.Len(t, index.Entries, 2, "expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) vs = index.Entries["compressedchart"] - if len(vs) != 1 { - t.Errorf("expected 1 versions, got %d: %#v", len(vs), vs) - } + assert.Len(t, vs, 1, "expected 1 versions, got %d: %#v", len(vs), vs) expectedVersion = "0.3.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) } func linkOrCopy(source, target string) error { diff --git a/pkg/getter/ocigetter_test.go b/pkg/getter/ocigetter_test.go index 5a7c99ebe..dfcc74890 100644 --- a/pkg/getter/ocigetter_test.go +++ b/pkg/getter/ocigetter_test.go @@ -21,18 +21,18 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/registry" ) func TestOCIGetter(t *testing.T) { g, err := NewOCIGetter(WithURL("oci://example.com")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := g.(*OCIGetter); !ok { - t.Fatal("Expected NewOCIGetter to produce an *OCIGetter") - } + _, ok := g.(*OCIGetter) + require.True(t, ok, "Expected NewOCIGetter to produce an *OCIGetter") cd := "../../testdata" join := filepath.Join @@ -51,71 +51,41 @@ func TestOCIGetter(t *testing.T) { WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS), WithPlainHTTP(plainHTTP), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) og, ok := g.(*OCIGetter) - if !ok { - t.Fatal("expected NewOCIGetter to produce an *OCIGetter") - } + require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") - if og.opts.username != "I" { - t.Errorf("Expected NewOCIGetter to contain %q as the username, got %q", "I", og.opts.username) - } + assert.Equal(t, "I", og.opts.username, "Expected NewOCIGetter to contain %q as the username, got %q", "I", og.opts.username) - if og.opts.password != "Am" { - t.Errorf("Expected NewOCIGetter to contain %q as the password, got %q", "Am", og.opts.password) - } + assert.Equal(t, "Am", og.opts.password, "Expected NewOCIGetter to contain %q as the password, got %q", "Am", og.opts.password) - if og.opts.certFile != pub { - t.Errorf("Expected NewOCIGetter to contain %q as the public key file, got %q", pub, og.opts.certFile) - } + assert.Equal(t, pub, og.opts.certFile, "Expected NewOCIGetter to contain %q as the public key file, got %q", pub, og.opts.certFile) - if og.opts.keyFile != priv { - t.Errorf("Expected NewOCIGetter to contain %q as the private key file, got %q", priv, og.opts.keyFile) - } + assert.Equal(t, priv, og.opts.keyFile, "Expected NewOCIGetter to contain %q as the private key file, got %q", priv, og.opts.keyFile) - if og.opts.caFile != ca { - t.Errorf("Expected NewOCIGetter to contain %q as the CA file, got %q", ca, og.opts.caFile) - } + assert.Equal(t, ca, og.opts.caFile, "Expected NewOCIGetter to contain %q as the CA file, got %q", ca, og.opts.caFile) - if og.opts.timeout != timeout { - t.Errorf("Expected NewOCIGetter to contain %s as Timeout flag, got %s", timeout, og.opts.timeout) - } + assert.Equal(t, timeout, og.opts.timeout, "Expected NewOCIGetter to contain %s as Timeout flag, got %s", timeout, og.opts.timeout) - if og.opts.transport != transport { - t.Errorf("Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) - } + assert.Equal(t, transport, og.opts.transport, "Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) - if og.opts.plainHTTP != plainHTTP { - t.Errorf("Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) - } + assert.Equal(t, plainHTTP, og.opts.plainHTTP, "Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) - if og.opts.insecureSkipVerifyTLS != insecureSkipVerifyTLS { - t.Errorf("Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) - } + assert.Equal(t, insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS, "Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) g, err = NewOCIGetter( WithRegistryClient(registryClient), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) og, ok = g.(*OCIGetter) - if !ok { - t.Fatal("expected NewOCIGetter to produce an *OCIGetter") - } + require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") - if og.opts.registryClient != registryClient { - t.Errorf("Expected NewOCIGetter to contain %p as RegistryClient, got %p", registryClient, og.opts.registryClient) - } + assert.Equal(t, registryClient, og.opts.registryClient, "Expected NewOCIGetter to contain %p as RegistryClient, got %p", registryClient, og.opts.registryClient) } func TestOCIHTTPTransportReuse(t *testing.T) { @@ -123,29 +93,19 @@ func TestOCIHTTPTransportReuse(t *testing.T) { _, err := g.newRegistryClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if g.transport == nil { - t.Fatal("Expected non nil value for transport") - } + require.NotNil(t, g.transport, "Expected non nil value for transport") transport1 := g.transport _, err = g.newRegistryClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if g.transport == nil { - t.Fatal("Expected non nil value for transport") - } + require.NotNil(t, g.transport, "Expected non nil value for transport") transport2 := g.transport - if transport1 != transport2 { - t.Fatal("Expected default transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected default transport to be reused") } From 4073566e285d5bfaafaf0cec2b927fa037bfcb2a Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:55 +0200 Subject: [PATCH 108/161] chore(pkg): refactor: convert tests to testify assert/require part 17 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/action/uninstall_test.go | 4 +- pkg/chart/common/capabilities_test.go | 80 +++++++----------------- pkg/chart/v2/lint/rules/template_test.go | 71 +++++---------------- pkg/cmd/dependency_build_test.go | 67 +++++++------------- pkg/cmd/plugin_package_test.go | 75 +++++++--------------- pkg/cmd/repo_add_test.go | 76 ++++++---------------- 6 files changed, 108 insertions(+), 265 deletions(-) diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 913ade1a5..f36fe7874 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -121,7 +121,7 @@ func TestUninstallRelease_Wait(t *testing.T) { unAction.cfg.KubeClient = failer resi, err := unAction.Run(rel.Name) req.Error(err) - is.Contains(err.Error(), "U timed out") + req.ErrorContains(err, "U timed out") res, err := releaserToV1Release(resi.Release) req.NoError(err) is.Equal(common.StatusUninstalled, res.Info.Status) @@ -163,7 +163,7 @@ func TestUninstallRelease_Cascade(t *testing.T) { unAction.cfg.KubeClient = failer _, err := unAction.Run(rel.Name) require.Error(t, err) - is.Contains(err.Error(), "failed to delete release: come-fail-away") + is.ErrorContains(err, "failed to delete release: come-fail-away") } func TestUninstallRun_UnreachableKubeClient(t *testing.T) { diff --git a/pkg/chart/common/capabilities_test.go b/pkg/chart/common/capabilities_test.go index c8d47581c..b099e3193 100644 --- a/pkg/chart/common/capabilities_test.go +++ b/pkg/chart/common/capabilities_test.go @@ -17,68 +17,44 @@ package common import ( "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestVersionSet(t *testing.T) { vs := VersionSet{"v1", "apps/v1"} - if d := len(vs); d != 2 { - t.Errorf("Expected 2 versions, got %d", d) - } + d := len(vs) + assert.Equalf(t, 2, d, "Expected 2 versions, got %d", d) - if !vs.Has("apps/v1") { - t.Error("Expected to find apps/v1") - } + assert.True(t, vs.Has("apps/v1"), "Expected to find apps/v1") - if vs.Has("Spanish/inquisition") { - t.Error("No one expects the Spanish/inquisition") - } + assert.False(t, vs.Has("Spanish/inquisition"), "No one expects the Spanish/inquisition") } func TestDefaultVersionSet(t *testing.T) { - if !DefaultVersionSet.Has("v1") { - t.Error("Expected core v1 version set") - } + assert.True(t, DefaultVersionSet.Has("v1"), "Expected core v1 version set") } func TestDefaultCapabilities(t *testing.T) { caps := DefaultCapabilities kv := caps.KubeVersion - if kv.String() != "v1.20.0" { - t.Errorf("Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String()) - } - if kv.Version != "v1.20.0" { - t.Errorf("Expected default KubeVersion.Version to be v1.20.0, got %q", kv.Version) - } - if kv.GitVersion() != "v1.20.0" { - t.Errorf("Expected default KubeVersion.GitVersion() to be v1.20.0, got %q", kv.Version) - } - if kv.Major != "1" { - t.Errorf("Expected default KubeVersion.Major to be 1, got %q", kv.Major) - } - if kv.Minor != "20" { - t.Errorf("Expected default KubeVersion.Minor to be 20, got %q", kv.Minor) - } + assert.Equalf(t, "v1.20.0", kv.String(), "Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String()) + assert.Equalf(t, "v1.20.0", kv.Version, "Expected default KubeVersion.Version to be v1.20.0, got %q", kv.Version) + assert.Equalf(t, "v1.20.0", kv.GitVersion(), "Expected default KubeVersion.GitVersion() to be v1.20.0, got %q", kv.Version) + assert.Equalf(t, "1", kv.Major, "Expected default KubeVersion.Major to be 1, got %q", kv.Major) + assert.Equalf(t, "20", kv.Minor, "Expected default KubeVersion.Minor to be 20, got %q", kv.Minor) hv := caps.HelmVersion - if hv.Version != "v4.2" { - t.Errorf("Expected default HelmVersion to be v4.2, got %q", hv.Version) - } + assert.Equalf(t, "v4.2", hv.Version, "Expected default HelmVersion to be v4.2, got %q", hv.Version) } func TestParseKubeVersion(t *testing.T) { kv, err := ParseKubeVersion("v1.16.0") - if err != nil { - t.Error("Expected v1.16.0 to parse successfully") - } - if kv.Version != "v1.16.0" { - t.Errorf("Expected parsed KubeVersion.Version to be v1.16.0, got %q", kv.String()) - } - if kv.Major != "1" { - t.Errorf("Expected parsed KubeVersion.Major to be 1, got %q", kv.Major) - } - if kv.Minor != "16" { - t.Errorf("Expected parsed KubeVersion.Minor to be 16, got %q", kv.Minor) - } + require.NoError(t, err, "Expected v1.16.0 to parse successfully") + assert.Equalf(t, "v1.16.0", kv.Version, "Expected parsed KubeVersion.Version to be v1.16.0, got %q", kv.String()) + assert.Equalf(t, "1", kv.Major, "Expected parsed KubeVersion.Major to be 1, got %q", kv.Major) + assert.Equalf(t, "16", kv.Minor, "Expected parsed KubeVersion.Minor to be 16, got %q", kv.Minor) } func TestParseKubeVersionWithVendorSuffixes(t *testing.T) { @@ -101,21 +77,11 @@ func TestParseKubeVersionWithVendorSuffixes(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { kv, err := ParseKubeVersion(tt.input) - if err != nil { - t.Fatalf("ParseKubeVersion() error = %v", err) - } - if kv.Version != tt.wantVer { - t.Errorf("Version = %q, want %q", kv.Version, tt.wantVer) - } - if kv.String() != tt.wantString { - t.Errorf("String() = %q, want %q", kv.String(), tt.wantString) - } - if kv.Major != tt.wantMajor { - t.Errorf("Major = %q, want %q", kv.Major, tt.wantMajor) - } - if kv.Minor != tt.wantMinor { - t.Errorf("Minor = %q, want %q", kv.Minor, tt.wantMinor) - } + require.NoErrorf(t, err, "ParseKubeVersion()") + assert.Equalf(t, tt.wantVer, kv.Version, "Version = %q, want %q", kv.Version, tt.wantVer) + assert.Equalf(t, tt.wantString, kv.String(), "String() = %q, want %q", kv.String(), tt.wantString) + assert.Equalf(t, tt.wantMajor, kv.Major, "Major = %q, want %q", kv.Major, tt.wantMajor) + assert.Equalf(t, tt.wantMinor, kv.Minor, "Minor = %q, want %q", kv.Minor, tt.wantMinor) }) } } diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index 12eec7531..37a33a7eb 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -20,7 +20,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" "time" @@ -38,17 +37,11 @@ const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { - err := validateAllowedExtension(test) - if err == nil || !strings.Contains(err.Error(), "Valid extensions are .yaml, .yml, .tpl, or .txt") { - t.Errorf("validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) - } + require.ErrorContainsf(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { - err := validateAllowedExtension(test) - if err != nil { - t.Errorf("validateAllowedExtension('%s') to return no error but got \"%s\"", test, err.Error()) - } + assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } } @@ -65,13 +58,8 @@ func TestTemplateParsing(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected one error, got %d, %v", len(res), res) - } - - if !strings.Contains(res[0].Err.Error(), "deliberateSyntaxError") { - t.Errorf("Unexpected error: %s", res[0]) - } + require.Len(t, res, 1, "Expected one error, got %d, %v", len(res), res) + assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") @@ -92,9 +80,7 @@ func TestTemplateIntegrationHappyPath(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 0 { - t.Fatalf("Expected no error, got %d, %v", len(res), res) - } + require.Empty(t, res, "Expected no error, got %d, %v", len(res), res) } func TestMultiTemplateFail(t *testing.T) { @@ -106,13 +92,8 @@ func TestMultiTemplateFail(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected 1 error, got %d, %v", len(res), res) - } - - if !strings.Contains(res[0].Err.Error(), "object name does not conform to Kubernetes naming requirements") { - t.Errorf("Unexpected error: %s", res[0].Err) - } + require.Len(t, res, 1, "Expected 1 error, got %d, %v", len(res), res) + assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements") } func TestValidateMetadataName(t *testing.T) { @@ -221,9 +202,7 @@ func TestDeprecatedAPIFails(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates( @@ -279,9 +258,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { }, } dir := t.TempDir() - if err := chartutil.SaveDir(&ch, dir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&ch, dir)) linter := &support.Linter{ ChartDir: filepath.Join(dir, ch.Metadata.Name), } @@ -327,9 +304,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -351,9 +326,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -372,9 +345,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err == nil { - t.Error("expected Deployment with no selector to fail") - } + assert.Error(t, validateMatchSelector(md, manifest), "expected Deployment with no selector to fail") } func TestValidateTopIndentLevel(t *testing.T) { @@ -413,9 +384,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates( @@ -448,10 +417,7 @@ items: annotations: helm.sh/resource-policy: keep ` - - if err := validateListAnnotations(md, manifest); err == nil { - t.Fatal("expected list with nested keep annotations to fail") - } + require.Error(t, validateListAnnotations(md, manifest), "expected list with nested keep annotations to fail") manifest = ` apiVersion: v1 @@ -463,10 +429,7 @@ items: - apiVersion: v1 kind: ConfigMap ` - - if err := validateListAnnotations(md, manifest); err != nil { - t.Fatalf("List objects keep annotations should pass. got: %s", err) - } + require.NoErrorf(t, validateListAnnotations(md, manifest), "List objects keep annotations should pass. got") } func TestIsYamlFileExtension(t *testing.T) { @@ -482,8 +445,6 @@ func TestIsYamlFileExtension(t *testing.T) { for _, test := range tests { result := isYamlFileExtension(test.filename) - if result != test.expected { - t.Errorf("isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) - } + assert.Equal(t, test.expected, result, "isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) } } diff --git a/pkg/cmd/dependency_build_test.go b/pkg/cmd/dependency_build_test.go index 7b3bea28a..485ae18b3 100644 --- a/pkg/cmd/dependency_build_test.go +++ b/pkg/cmd/dependency_build_test.go @@ -19,9 +19,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chartutil "helm.sh/helm/v4/pkg/chart/v2/util" "helm.sh/helm/v4/pkg/provenance" "helm.sh/helm/v4/pkg/repo/v1" @@ -39,15 +41,12 @@ func TestDependencyBuildCmd(t *testing.T) { srv.LinkIndices() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociChartName := "oci-depending-chart" c := createTestingMetadataForOCI(ociChartName, ociSrv.RegistryURL) - if _, err := chartutil.Save(c, ociSrv.Dir); err != nil { - t.Fatal(err) - } + _, err = chartutil.Save(c, ociSrv.Dir) + require.NoError(t, err) ociSrv.Run(t, repotest.WithDependingChart(c)) dir := func(p ...string) string { @@ -67,25 +66,19 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } - if !strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did not get updated\n%s", out) - } + assert.Contains(t, out, `update from the "test" chart repository`, "Repo did not get updated\n%s", out) // Make sure the actual file got downloaded. expect := filepath.Join(rootDir, chartname, "charts", "reqtest-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) // In the second pass, we want to remove the chart's request dependency, // then see if it restores from the lock. lockfile := filepath.Join(rootDir, chartname, "Chart.lock") - if _, err := os.Stat(lockfile); err != nil { - t.Fatal(err) - } - if err := os.RemoveAll(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(lockfile) + require.NoError(t, err) + require.NoError(t, os.RemoveAll(expect)) _, out, err = executeActionCommand(cmd) if err != nil { @@ -94,28 +87,21 @@ func TestDependencyBuildCmd(t *testing.T) { } // Now repeat the test that the dependency exists. - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) // Make sure that build is also fetching the correct version. hash, err := provenance.DigestFile(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) i, err := repo.LoadIndexFile(filepath.Join(rootDir, "index.yaml")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) reqver := i.Entries["reqtest"][0] - if h := reqver.Digest; h != hash { - t.Errorf("Failed hash match: expected %s, got %s", hash, h) - } - if v := reqver.Version; v != "0.1.0" { - t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v) - } + h := reqver.Digest + assert.Equalf(t, h, hash, "Failed hash match: expected %s, got %s", hash, h) + v := reqver.Version + assert.Equalf(t, "0.1.0", v, "mismatched versions. Expected %q, got %q", "0.1.0", v) skipRefreshCmd := fmt.Sprintf("dependency build '%s' --skip-refresh --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir) _, out, err = executeActionCommand(skipRefreshCmd) @@ -126,14 +112,10 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } - if strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did get updated\n%s", out) - } + assert.NotContains(t, out, `update from the "test" chart repository`, "Repo did get updated\n%s", out) // OCI dependencies - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) cmd = fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --plain-http", dir(ociChartName), dir("repositories.yaml"), @@ -145,9 +127,8 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } expect = dir(ociChartName, "charts/oci-dependent-chart-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) } func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) { diff --git a/pkg/cmd/plugin_package_test.go b/pkg/cmd/plugin_package_test.go index b5ecf2bf1..e04498b98 100644 --- a/pkg/cmd/plugin_package_test.go +++ b/pkg/cmd/plugin_package_test.go @@ -19,8 +19,10 @@ import ( "bytes" "os" "path/filepath" - "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // Common plugin.yaml content for v1 format tests @@ -43,14 +45,10 @@ func TestPluginPackageWithoutSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with sign=false o := &pluginPackageOptions{ @@ -61,47 +59,34 @@ func TestPluginPackageWithoutSigning(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should succeed without error - if err != nil { - t.Errorf("unexpected error: %v", err) - } + require.NoError(t, o.run(out)) // Check that tarball was created with plugin name and version tarballPath := filepath.Join(tempDir, "test-plugin-1.0.0.tgz") - if _, err := os.Stat(tarballPath); os.IsNotExist(err) { - t.Error("tarball should exist when sign=false") - } + _, err := os.Stat(tarballPath) + assert.False(t, os.IsNotExist(err), "tarball should exist when sign=false") // Check that no .prov file was created provPath := tarballPath + ".prov" - if _, err := os.Stat(provPath); !os.IsNotExist(err) { - t.Error("provenance file should not exist when sign=false") - } + _, err = os.Stat(provPath) + assert.True(t, os.IsNotExist(err), "provenance file should not exist when sign=false") // Output should contain warning about skipping signing output := out.String() - if !strings.Contains(output, "WARNING: Skipping plugin signing") { - t.Error("should print warning when signing is skipped") - } - if !strings.Contains(output, "Successfully packaged") { - t.Error("should print success message") - } + assert.Contains(t, output, "WARNING: Skipping plugin signing", "should print warning when signing is skipped") + assert.Contains(t, output, "Successfully packaged", "should print success message") } func TestPluginPackageDefaultRequiresSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with default sign=true and invalid keyring o := &pluginPackageOptions{ @@ -113,32 +98,24 @@ func TestPluginPackageDefaultRequiresSigning(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should fail because signing is required by default - if err == nil { - t.Error("expected error when signing fails with default settings") - } + require.Error(t, o.run(out), "expected error when signing fails with default settings") // Check that no tarball was created tarballPath := filepath.Join(tempDir, "test-plugin.tgz") - if _, err := os.Stat(tarballPath); !os.IsNotExist(err) { - t.Error("tarball should not exist when signing fails") - } + _, err := os.Stat(tarballPath) + assert.True(t, os.IsNotExist(err), "tarball should not exist when signing fails") } func TestPluginPackageSigningFailure(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with sign flag but invalid keyring o := &pluginPackageOptions{ @@ -150,21 +127,15 @@ func TestPluginPackageSigningFailure(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should get an error - if err == nil { - t.Error("expected error when signing fails, got nil") - } + require.Error(t, o.run(out), "expected error when signing fails, got nil") // Check that no tarball was created tarballPath := filepath.Join(tempDir, "test-plugin.tgz") - if _, err := os.Stat(tarballPath); !os.IsNotExist(err) { - t.Error("tarball should not exist when signing fails") - } + _, err := os.Stat(tarballPath) + assert.True(t, os.IsNotExist(err), "tarball should not exist when signing fails") // Output should not contain success message - if bytes.Contains(out.Bytes(), []byte("Successfully packaged")) { - t.Error("should not print success message when signing fails") - } + assert.False(t, bytes.Contains(out.Bytes(), []byte("Successfully packaged")), "should not print success message when signing fails") } diff --git a/pkg/cmd/repo_add_test.go b/pkg/cmd/repo_add_test.go index ed677f98a..6ed2a7422 100644 --- a/pkg/cmd/repo_add_test.go +++ b/pkg/cmd/repo_add_test.go @@ -17,16 +17,16 @@ limitations under the License. package cmd import ( - "errors" "fmt" "io" "io/fs" "os" "path/filepath" - "strings" "sync" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" "helm.sh/helm/v4/pkg/helmpath" @@ -50,9 +50,7 @@ func TestRepoAddCmd(t *testing.T) { defer srv2.Stop() tmpdir := filepath.Join(t.TempDir(), "path-component.yaml", "data") - if err := os.MkdirAll(tmpdir, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(tmpdir, 0o777)) repoFile := filepath.Join(tmpdir, "repositories.yaml") tests := []cmdTestCase{ @@ -101,37 +99,24 @@ func TestRepoAdd(t *testing.T) { } t.Setenv(xdg.CacheHomeEnvVar, rootDir) - if err := o.run(io.Discard); err != nil { - t.Error(err) - } + require.NoError(t, o.run(io.Discard)) f, err := repo.LoadFile(repoFile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !f.Has(testRepoName) { - t.Errorf("%s was not successfully inserted into %s", testRepoName, repoFile) - } + assert.Truef(t, f.Has(testRepoName), "%s was not successfully inserted into %s", testRepoName, repoFile) idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName)) - if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) { - t.Errorf("Error cache index file was not created for repository %s", testRepoName) - } + _, err = os.Stat(idx) + require.NotErrorIsf(t, err, fs.ErrNotExist, "Error cache index file was not created for repository %s", testRepoName) idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName)) - if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) { - t.Errorf("Error cache charts file was not created for repository %s", testRepoName) - } + _, err = os.Stat(idx) + require.NotErrorIsf(t, err, fs.ErrNotExist, "Error cache charts file was not created for repository %s", testRepoName) o.forceUpdate = true - if err := o.run(io.Discard); err != nil { - t.Errorf("Repository was not updated: %s", err) - } - - if err := o.run(io.Discard); err != nil { - t.Error("Duplicate repository name was added") - } + require.NoError(t, o.run(io.Discard), "Repository was not updated") + assert.NoError(t, o.run(io.Discard), "Duplicate repository name was added") } func TestRepoAddCheckLegalName(t *testing.T) { @@ -156,14 +141,7 @@ func TestRepoAddCheckLegalName(t *testing.T) { t.Setenv(xdg.CacheHomeEnvVar, rootDir) wantErrorMsg := fmt.Sprintf("repository name (%s) contains '/', please specify a different name without '/'", testRepoName) - - if err := o.run(io.Discard); err != nil { - if wantErrorMsg != err.Error() { - t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg) - } - } else { - t.Fatal("expect reported an error.") - } + require.EqualError(t, o.run(io.Discard), wantErrorMsg) } func TestRepoAddConcurrentGoRoutines(t *testing.T) { @@ -209,29 +187,21 @@ func repoAddConcurrent(t *testing.T, testName, repoFile string) { forceUpdate: false, repoFile: repoFile, } - if err := o.run(io.Discard); err != nil { - t.Error(err) - } + assert.NoError(t, o.run(io.Discard)) }(fmt.Sprintf("%s-%d", testName, i)) } wg.Wait() b, err := os.ReadFile(repoFile) - if err != nil { - t.Error(err) - } + require.NoError(t, err) var f repo.File - if err := yaml.Unmarshal(b, &f); err != nil { - t.Error(err) - } + require.NoError(t, yaml.Unmarshal(b, &f)) var name string for i := range 3 { name = fmt.Sprintf("%s-%d", testName, i) - if !f.Has(name) { - t.Errorf("%s was not successfully inserted into %s: %s", name, repoFile, f.Repositories[0]) - } + assert.Truef(t, f.Has(name), "%s was not successfully inserted into %s: %s", name, repoFile, f.Repositories[0]) } } @@ -252,9 +222,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { defer resetEnv()() in, err := os.Open("testdata/password") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) tmpdir := t.TempDir() repoFile := filepath.Join(tmpdir, "repositories.yaml") @@ -266,11 +234,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { cmd := fmt.Sprintf("repo add %s %s --repository-config %s --repository-cache %s --username %s --password-stdin", testName, srv.URL(), repoFile, tmpdir, username) var result string _, result, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - if !strings.Contains(result, fmt.Sprintf("%q has been added to your repositories", testName)) { - t.Errorf("Repo was not successfully added. Output: %s", result) - } + require.NoError(t, err) + assert.Contains(t, result, fmt.Sprintf("%q has been added to your repositories", testName), "Repo was not successfully added. Output: %s", result) } From 0fa9f7d427b99437e51dbb8ada21d19f93898652 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 109/161] chore(pkg): refactor: convert tests to testify assert/require part 16 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/action/get_metadata_test.go | 6 +- pkg/chart/common/values_test.go | 116 ++++++++++++------------------- pkg/chart/v2/util/expand_test.go | 92 +++++++----------------- pkg/cmd/plugin_verify_test.go | 83 +++++----------------- pkg/cmd/pull_test.go | 105 +++++++++------------------- 5 files changed, 120 insertions(+), 282 deletions(-) diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index 37f20fb60..f8851e456 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -65,8 +65,7 @@ func TestGetMetadata_Run_BasicMetadata(t *testing.T) { Namespace: "default", } - err := cfg.Releases.Create(rel) - require.NoError(t, err) + require.NoError(t, cfg.Releases.Create(rel)) result, err := client.Run(releaseName) require.NoError(t, err) @@ -645,8 +644,7 @@ func TestGetMetadata_Labels(t *testing.T) { rel.Labels = customLabels metaGetter := NewGetMetadata(actionConfigFixture(t)) - err := metaGetter.cfg.Releases.Create(rel) - require.NoError(t, err) + require.NoError(t, metaGetter.cfg.Releases.Create(rel)) metadata, err := metaGetter.Run(rel.Name) require.NoError(t, err) diff --git a/pkg/chart/common/values_test.go b/pkg/chart/common/values_test.go index 9743869ec..803513c32 100644 --- a/pkg/chart/common/values_test.go +++ b/pkg/chart/common/values_test.go @@ -21,6 +21,9 @@ import ( "fmt" "testing" "text/template" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestReadValues(t *testing.T) { @@ -46,29 +49,21 @@ water: ` data, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Error parsing bytes: %s", err) - } + require.NoErrorf(t, err, "Error parsing bytes") matchValues(t, data) tests := []string{`poet: "Coleridge"`, "# Just a comment", ""} for _, tt := range tests { data, err = ReadValues([]byte(tt)) - if err != nil { - t.Fatalf("Error parsing bytes (%s): %s", tt, err) - } - if data == nil { - t.Errorf(`YAML string "%s" gave a nil map`, tt) - } + require.NoErrorf(t, err, "Error parsing bytes (%s)", tt) + require.NotNilf(t, data, `YAML string "%s" gave a nil map`, tt) } } func TestReadValuesFile(t *testing.T) { data, err := ReadValuesFile("./testdata/coleridge.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoErrorf(t, err, "Error reading YAML file") matchValues(t, data) } @@ -108,56 +103,40 @@ chapter: title: "The Spouter Inn" ` d, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Failed to parse the White Whale: %s", err) - } + require.NoErrorf(t, err, "Failed to parse the White Whale") - if _, err := d.Table("title"); err == nil { - t.Fatal("Title is not a table.") - } + _, err = d.Table("title") + require.Error(t, err, "Title is not a table.") - if _, err := d.Table("chapter"); err != nil { - t.Fatalf("Failed to get the chapter table: %s\n%v", err, d) - } + _, err = d.Table("chapter") + require.NoErrorf(t, err, "Failed to get the chapter table: %v", d) - if v, err := d.Table("chapter.one"); err != nil { - t.Errorf("Failed to get chapter.one: %s", err) - } else if v["title"] != "Loomings" { - t.Errorf("Unexpected title: %s", v["title"]) - } + v, err := d.Table("chapter.one") + require.NoErrorf(t, err, "Failed to get chapter.one") + assert.Equalf(t, "Loomings", v["title"], "Unexpected title: %s", v["title"]) - if _, err := d.Table("chapter.three"); err != nil { - t.Errorf("Chapter three is missing: %s\n%v", err, d) - } + _, err = d.Table("chapter.three") + require.NoErrorf(t, err, "Chapter three is missing: %v", d) - if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil { - t.Error("I think you mean 'Epilogue'") - } + _, err = d.Table("chapter.OneHundredThirtySix") + assert.Error(t, err, "I think you mean 'Epilogue'") } func matchValues(t *testing.T, data map[string]any) { t.Helper() - if data["poet"] != "Coleridge" { - t.Errorf("Unexpected poet: %s", data["poet"]) - } + assert.Equalf(t, "Coleridge", data["poet"], "Unexpected poet: %s", data["poet"]) - if o, err := ttpl("{{len .stanza}}", data); err != nil { - t.Errorf("len stanza: %s", err) - } else if o != "6" { - t.Errorf("Expected 6, got %s", o) - } + o, err := ttpl("{{len .stanza}}", data) + require.NoErrorf(t, err, "len stanza") + assert.Equalf(t, "6", o, "Expected 6, got %s", o) - if o, err := ttpl("{{.mariner.shot}}", data); err != nil { - t.Errorf(".mariner.shot: %s", err) - } else if o != "ALBATROSS" { - t.Error("Expected that mariner shot ALBATROSS") - } + o, err = ttpl("{{.mariner.shot}}", data) + require.NoErrorf(t, err, ".mariner.shot") + assert.Equal(t, "ALBATROSS", o, "Expected that mariner shot ALBATROSS") - if o, err := ttpl("{{.water.water.where}}", data); err != nil { - t.Errorf(".water.water.where: %s", err) - } else if o != "everywhere" { - t.Error("Expected water water everywhere") - } + o, err = ttpl("{{.water.water.where}}", data) + require.NoErrorf(t, err, ".water.water.where") + assert.Equal(t, "everywhere", o, "Expected water water everywhere") } func ttpl(tpl string, v map[string]any) (string, error) { @@ -179,27 +158,18 @@ chapter: title: "The Spouter Inn" ` d, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Failed to parse the White Whale: %s", err) - } - - if v, err := d.PathValue("chapter.one.title"); err != nil { - t.Errorf("Got error instead of title: %s\n%v", err, d) - } else if v != "Loomings" { - t.Errorf("No error but got wrong value for title: %s\n%v", err, d) - } - if _, err := d.PathValue("chapter.one.doesnotexist"); err == nil { - t.Errorf("Non-existent key should return error: %s\n%v", err, d) - } - if _, err := d.PathValue("chapter.doesnotexist.one"); err == nil { - t.Errorf("Non-existent key in middle of path should return error: %s\n%v", err, d) - } - if _, err := d.PathValue(""); err == nil { - t.Error("Asking for the value from an empty path should yield an error") - } - if v, err := d.PathValue("title"); err == nil { - if v != "Moby Dick" { - t.Error("Failed to return values for root key title") - } - } + require.NoErrorf(t, err, "Failed to parse the White Whale") + + v, err := d.PathValue("chapter.one.title") + require.NoErrorf(t, err, "Got error instead of title: %v", d) + assert.Equalf(t, "Loomings", v, "No error but got wrong value for title: %v", d) + _, err = d.PathValue("chapter.one.doesnotexist") + require.Errorf(t, err, "Non-existent key should return error: %v", d) + _, err = d.PathValue("chapter.doesnotexist.one") + require.Errorf(t, err, "Non-existent key in middle of path should return error: %v", d) + _, err = d.PathValue("") + require.Error(t, err, "Asking for the value from an empty path should yield an error") + v, err = d.PathValue("title") + require.NoErrorf(t, err, "Failed to get title: %v", d) + assert.Equalf(t, "Moby Dick", v, "Failed to return values for root key title: got %s\n%v", v, d) } diff --git a/pkg/chart/v2/util/expand_test.go b/pkg/chart/v2/util/expand_test.go index e9e298b81..bc8cc7855 100644 --- a/pkg/chart/v2/util/expand_test.go +++ b/pkg/chart/v2/util/expand_test.go @@ -47,19 +47,18 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff fStat, err := f.Stat() require.NoError(t, err) - err = tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: filepath.Join(chartName, relPath), Mode: int64(fStat.Mode()), Size: fStat.Size(), - }) - require.NoError(t, err) + })) data, err := fs.ReadFile(dir, relPath) require.NoError(t, err) tw.Write(data) } - err := fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { + require.NoError(t, fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr } @@ -71,15 +70,9 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff writeFile(path) return nil - }) - if err != nil { - t.Fatal(err) - } - - err = tw.Close() - require.NoError(t, err) - err = gw.Close() - require.NoError(t, err) + })) + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) return &result } @@ -88,51 +81,33 @@ func TestExpand(t *testing.T) { dest := t.TempDir() reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if err := Expand(dest, reader); err != nil { - t.Fatal(err) - } + require.NoError(t, Expand(dest, reader)) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.NoError(t, err) + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } @@ -151,10 +126,9 @@ func TestExpandError(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { archive := makeTestChartArchive(t, tt.chartName, tt.chartDir) - dest := t.TempDir() - err := Expand(dest, archive) - assert.ErrorContains(t, err, tt.wantErr) + + assert.ErrorContains(t, Expand(dest, archive), tt.wantErr) }) } } @@ -162,47 +136,31 @@ func TestExpandError(t *testing.T) { func TestExpandFile(t *testing.T) { dest := t.TempDir() - if err := ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz"); err != nil { - t.Fatal(err) - } + require.NoError(t, ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz")) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.NoError(t, err) + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } diff --git a/pkg/cmd/plugin_verify_test.go b/pkg/cmd/plugin_verify_test.go index 4ce664c0c..64e6cc18c 100644 --- a/pkg/cmd/plugin_verify_test.go +++ b/pkg/cmd/plugin_verify_test.go @@ -21,9 +21,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" ) @@ -35,13 +37,7 @@ func TestPluginVerifyCmd_NoArgs(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when no arguments provided") - } - if !strings.Contains(err.Error(), "requires 1 argument") { - t.Errorf("expected 'requires 1 argument' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "requires 1 argument", "expected 'requires 1 argument' error") } func TestPluginVerifyCmd_TooManyArgs(t *testing.T) { @@ -51,13 +47,7 @@ func TestPluginVerifyCmd_TooManyArgs(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{"plugin1", "plugin2"}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when too many arguments provided") - } - if !strings.Contains(err.Error(), "requires 1 argument") { - t.Errorf("expected 'requires 1 argument' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "requires 1 argument", "expected 'requires 1 argument' error") } func TestPluginVerifyCmd_NonexistentFile(t *testing.T) { @@ -67,10 +57,7 @@ func TestPluginVerifyCmd_NonexistentFile(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{"/nonexistent/plugin.tgz"}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when plugin file doesn't exist") - } + assert.Error(t, cmd.Execute(), "expected error when plugin file doesn't exist") } func TestPluginVerifyCmd_MissingProvenance(t *testing.T) { @@ -84,13 +71,7 @@ func TestPluginVerifyCmd_MissingProvenance(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginTgz}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when .prov file is missing") - } - if !strings.Contains(err.Error(), "could not find provenance file") { - t.Errorf("expected 'could not find provenance file' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "could not find provenance file", "expected 'could not find provenance file' error") } func TestPluginVerifyCmd_InvalidProvenance(t *testing.T) { @@ -102,19 +83,14 @@ func TestPluginVerifyCmd_InvalidProvenance(t *testing.T) { // Create invalid .prov file provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("invalid provenance"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(provFile, []byte("invalid provenance"), 0o644)) defer os.Remove(provFile) out := &bytes.Buffer{} cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginTgz}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when .prov file is invalid") - } + assert.Error(t, cmd.Execute(), "expected error when .prov file is invalid") } func TestPluginVerifyCmd_DirectoryNotSupported(t *testing.T) { @@ -127,13 +103,7 @@ func TestPluginVerifyCmd_DirectoryNotSupported(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginDir}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when verifying directory") - } - if !strings.Contains(err.Error(), "directory verification not supported") { - t.Errorf("expected 'directory verification not supported' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "directory verification not supported", "expected 'directory verification not supported' error") } func TestPluginVerifyCmd_KeyringFlag(t *testing.T) { @@ -157,10 +127,7 @@ func TestPluginVerifyCmd_KeyringFlag(t *testing.T) { cmd.SetArgs([]string{"--keyring", keyring, pluginTgz}) // Should fail with keyring error but command parsing should work - err := cmd.Execute() - if err == nil { - t.Error("expected error with empty keyring") - } + assert.Error(t, cmd.Execute(), "expected error with empty keyring") // The important thing is that the keyring flag was parsed and used } @@ -178,14 +145,10 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatalf("Failed to create plugin directory: %v", err) - } + require.NoErrorf(t, os.MkdirAll(pluginDir, 0o755), "Failed to create plugin directory") // Use the same plugin YAML as other cmd tests - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatalf("Failed to create plugin.yaml: %v", err) - } + require.NoErrorf(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644), "Failed to create plugin.yaml") return pluginDir } @@ -199,14 +162,10 @@ func createTestPluginTarball(t *testing.T) string { tmpDir := filepath.Dir(pluginDir) tgzPath := filepath.Join(tmpDir, "test-plugin-1.0.0.tgz") tarFile, err := os.Create(tgzPath) - if err != nil { - t.Fatalf("Failed to create tarball file: %v", err) - } + require.NoError(t, err, "Failed to create tarball file") defer tarFile.Close() - if err := plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { - t.Fatalf("Failed to create tarball: %v", err) - } + require.NoErrorf(t, plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile), "Failed to create tarball") return tgzPath } @@ -218,9 +177,7 @@ func createProvFile(t *testing.T, provFile, pluginTgz, hash string) { if hash == "" { // Calculate actual hash of the tarball data, err := os.ReadFile(pluginTgz) - if err != nil { - t.Fatalf("Failed to read tarball for hashing: %v", err) - } + require.NoError(t, err, "Failed to read tarball for hashing") hashSum := sha256.Sum256(data) hashStr = fmt.Sprintf("sha256:%x", hashSum) } else { @@ -243,9 +200,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { - t.Fatalf("Failed to create provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(provContent), 0o644), "Failed to create provenance file") } func createTestKeyring(t *testing.T) string { @@ -256,9 +211,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { - t.Fatalf("Failed to create test keyring: %v", err) - } + require.NoErrorf(t, os.WriteFile(keyringPath, []byte{}, 0o644), "Failed to create test keyring") return keyringPath } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index e1b3e8134..352c36a29 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -25,6 +25,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -36,14 +39,10 @@ func TestPullCmd(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociSrv.Run(t) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) helmTestKeyOut := "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) \n" + "Using Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\n" + @@ -229,20 +228,13 @@ func TestPullCmd(t *testing.T) { // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182 if tt.existFile != "" { file := filepath.Join(outdir, tt.existFile) - if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil { - t.Fatal(err) - } - _, err := os.Create(file) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Dir(file), 0o755)) + _, err = os.Create(file) + require.NoError(t, err) } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(file, 0o755)) } _, out, err := executeActionCommand(cmd) if err != nil { @@ -257,19 +249,13 @@ func TestPullCmd(t *testing.T) { if tt.expectVerify { outString := helmTestKeyOut + tt.expectSha + "\n" - if out != outString { - t.Errorf("%q: expected verification output %q, got %q", tt.name, outString, out) - } + assert.Equal(t, outString, out, "%q: expected verification output %q, got %q", tt.name, outString, out) } ef := filepath.Join(outdir, tt.expectFile) fi, err := os.Stat(ef) - if err != nil { - t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) - } - if fi.IsDir() != tt.expectDir { - t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) - } + require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) + assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) }) } } @@ -300,38 +286,24 @@ func runPullTests(t *testing.T, tests []struct { if tt.existFile != "" { file := filepath.Join(outdir, tt.existFile) _, err := os.Create(file) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(file, 0o755)) } _, _, err := executeActionCommand(cmd) - if tt.wantError && err == nil { - t.Fatalf("%q: expected error but got none", tt.name) - } - if err != nil { - if tt.wantError { - if tt.wantErrorMsg != "" && tt.wantErrorMsg != err.Error() { - t.Fatalf("Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) - } - return + if tt.wantError { + require.Error(t, err, "%q: expected error but got none", tt.name) + if tt.wantErrorMsg != "" { + require.EqualErrorf(t, err, tt.wantErrorMsg, "Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) } - t.Fatalf("%q reported error: %s", tt.name, err) - } - - ef := filepath.Join(outdir, tt.expectFile) - fi, err := os.Stat(ef) - if err != nil { - t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) - } - if fi.IsDir() != tt.expectDir { - t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) + } else { + require.NoError(t, err, "%q reported error", tt.name) + ef := filepath.Join(outdir, tt.expectFile) + fi, err := os.Stat(ef) + require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) + assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) } }) } @@ -362,9 +334,7 @@ func TestPullWithCredentialsCmd(t *testing.T) { })) defer srv2.Close() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) // all flags will get "-d outdir" appended. tests := []struct { @@ -445,14 +415,10 @@ func TestPullWithCredentialsCmdOCIRegistry(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociSrv.Run(t) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) // all flags will get "-d outdir" appended. tests := []struct { @@ -517,9 +483,7 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result := ociSrv.RunWithReturn(t) contentCache := t.TempDir() @@ -538,9 +502,7 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { ) _, _, err = executeActionCommand(cmd) - if err != nil { - t.Fatalf("pull with tag+digest failed: %v", err) - } + require.NoError(t, err, "pull with tag+digest failed") // Verify the file was downloaded // When digest is present, the filename uses the digest format (e.g. chart@sha256-hex.tgz) @@ -548,12 +510,9 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { if _, err := os.Stat(expectedFile); err != nil { // Try the digest-based filename; parse algorithm:hex to avoid fixed-offset assumptions algorithm, digestPart, ok := strings.Cut(result.PushedChart.Manifest.Digest, ":") - if !ok { - t.Fatalf("digest must be in algorithm:hex format, got %q", result.PushedChart.Manifest.Digest) - } + require.True(t, ok, "digest must be in algorithm:hex format, got %q", result.PushedChart.Manifest.Digest) expectedFile = filepath.Join(outdir, fmt.Sprintf("oci-dependent-chart@%s-%s.tgz", algorithm, digestPart)) - if _, err := os.Stat(expectedFile); err != nil { - t.Errorf("expected chart file not found: %v", err) - } + _, err := os.Stat(expectedFile) + assert.NoErrorf(t, err, "expected chart file not found") } } From fb8a62bf13cbc0ad78d0856678365b246b224997 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 110/161] chore(pkg): refactor: convert tests to testify assert/require part 18 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/action/package_test.go | 54 ++++----------- pkg/chart/v2/lint/rules/dependencies_test.go | 22 ++---- pkg/chart/v2/util/create_test.go | 71 ++++++-------------- pkg/cmd/plugin_uninstall_test.go | 66 +++++++----------- pkg/cmd/repo_remove_test.go | 62 ++++++----------- pkg/cmd/repo_update_test.go | 65 ++++++------------ pkg/kube/resource_test.go | 45 ++++--------- 7 files changed, 117 insertions(+), 268 deletions(-) diff --git a/pkg/action/package_test.go b/pkg/action/package_test.go index 9984b508a..421f34b33 100644 --- a/pkg/action/package_test.go +++ b/pkg/action/package_test.go @@ -17,7 +17,6 @@ limitations under the License. package action import ( - "errors" "os" "path" "testing" @@ -35,18 +34,12 @@ func TestPassphraseFileFetcher(t *testing.T) { testPkg := NewPackage() fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) - if err != nil { - t.Fatal("Unable to create passphraseFileFetcher", err) - } + require.NoError(t, err, "Unable to create passphraseFileFetcher") passphrase, err := fetcher("key") - if err != nil { - t.Fatal("Unable to fetch passphrase") - } + require.NoError(t, err, "Unable to fetch passphrase") - if string(passphrase) != secret { - t.Errorf("Expected %s got %s", secret, string(passphrase)) - } + assert.Equal(t, secret, string(passphrase), "Expected %s got %s", secret, string(passphrase)) } func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { @@ -55,18 +48,12 @@ func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { testPkg := NewPackage() fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) - if err != nil { - t.Fatal("Unable to create passphraseFileFetcher", err) - } + require.NoError(t, err, "Unable to create passphraseFileFetcher") passphrase, err := fetcher("key") - if err != nil { - t.Fatal("Unable to fetch passphrase") - } + require.NoError(t, err, "Unable to fetch passphrase") - if string(passphrase) != secret { - t.Errorf("Expected %s got %s", secret, string(passphrase)) - } + assert.Equal(t, secret, string(passphrase), "Expected %s got %s", secret, string(passphrase)) } func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) { @@ -74,21 +61,16 @@ func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) { testPkg := NewPackage() stdin, err := os.CreateTemp(directory, "non-existing") - if err != nil { - t.Fatal("Unable to create test file", err) - } + require.NoError(t, err, "Unable to create test file") - if _, err := testPkg.passphraseFileFetcher("-", stdin); err == nil { - t.Error("Expected passphraseFileFetcher returning an error") - } + _, err = testPkg.passphraseFileFetcher("-", stdin) + assert.Error(t, err, "Expected passphraseFileFetcher returning an error") } func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { testPkg := NewPackage() stdin, w, err := os.Pipe() - if err != nil { - t.Fatal("Unable to create pipe", err) - } + require.NoError(t, err, "Unable to create pipe") passphrase := "secret-from-stdin" @@ -99,18 +81,12 @@ func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { for range 4 { fetcher, err := testPkg.passphraseFileFetcher("-", stdin) - if err != nil { - t.Errorf("Expected passphraseFileFetcher to not return an error, but got %v", err) - } + require.NoError(t, err, "Expected passphraseFileFetcher to not return an error") pass, err := fetcher("key") - if err != nil { - t.Errorf("Expected passphraseFileFetcher invocation to succeed, failed with %v", err) - } + require.NoError(t, err, "Expected passphraseFileFetcher invocation to succeed") - if string(pass) != string(passphrase) { - t.Errorf("Expected multiple passphrase fetch to return %q, got %q", passphrase, pass) - } + assert.Equal(t, string(passphrase), string(pass), "Expected multiple passphrase fetch to return %q, got %q", passphrase, pass) } } @@ -148,9 +124,7 @@ func TestValidateVersion(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := validateVersion(tt.args.ver); err != nil { - if !errors.Is(err, tt.wantErr) { - t.Errorf("Expected {%v}, got {%v}", tt.wantErr, err) - } + assert.ErrorIs(t, err, tt.wantErr) } }) } diff --git a/pkg/chart/v2/lint/rules/dependencies_test.go b/pkg/chart/v2/lint/rules/dependencies_test.go index c50fc4b2d..c800887bd 100644 --- a/pkg/chart/v2/lint/rules/dependencies_test.go +++ b/pkg/chart/v2/lint/rules/dependencies_test.go @@ -19,6 +19,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -62,18 +65,12 @@ func chartWithBadDependencies() chart.Chart { func TestValidateDependencyInChartsDir(t *testing.T) { c := chartWithBadDependencies() - - if err := validateDependencyInChartsDir(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart directory") - } + assert.Error(t, validateDependencyInChartsDir(&c), "chart should have been flagged for missing deps in chart directory") } func TestValidateDependencyInMetadata(t *testing.T) { c := chartWithBadDependencies() - - if err := validateDependencyInMetadata(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart metadata") - } + assert.Error(t, validateDependencyInMetadata(&c), "chart should have been flagged for missing deps in chart metadata") } func TestValidateDependenciesUnique(t *testing.T) { @@ -131,9 +128,7 @@ func TestValidateDependenciesUnique(t *testing.T) { } for _, tt := range tests { - if err := validateDependenciesUnique(&tt.chart); err == nil { - t.Error("chart should have been flagged for dependency shadowing") - } + assert.Error(t, validateDependenciesUnique(&tt.chart), "chart should have been flagged for dependency shadowing") } } @@ -141,10 +136,7 @@ func TestDependencies(t *testing.T) { tmp := t.TempDir() c := chartWithBadDependencies() - err := chartutil.SaveDir(&c, tmp) - if err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&c, tmp)) linter := support.Linter{ChartDir: filepath.Join(tmp, c.Metadata.Name)} Dependencies(&linter) diff --git a/pkg/chart/v2/util/create_test.go b/pkg/chart/v2/util/create_test.go index 367b755d9..c85c4e3d4 100644 --- a/pkg/chart/v2/util/create_test.go +++ b/pkg/chart/v2/util/create_test.go @@ -22,6 +22,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" ) @@ -30,20 +33,13 @@ func TestCreate(t *testing.T) { tdir := t.TempDir() c, err := Create("foo", tdir) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dir := filepath.Join(tdir, "foo") mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } - - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + require.NoError(t, err, "Failed to load newly created chart %q", c) + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, @@ -58,9 +54,8 @@ func TestCreate(t *testing.T) { TestConnectionName, ValuesfileName, } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + assert.NoErrorf(t, err, "Expected %s file", f) } } @@ -74,38 +69,26 @@ func TestCreateFrom(t *testing.T) { } srcdir := "./testdata/frobnitz/charts/mariner" - if err := CreateFrom(cf, tdir, srcdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CreateFrom(cf, tdir, srcdir)) dir := filepath.Join(tdir, "foo") c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } - - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + require.NoError(t, err, "Failed to load newly created chart %q", c) + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, ValuesfileName, filepath.Join(TemplatesDir, "placeholder.tpl"), } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + require.NoErrorf(t, err, "Expected %s file", f) // Check each file to make sure has been replaced b, err := os.ReadFile(filepath.Join(dir, f)) - if err != nil { - t.Errorf("Unable to read file %s: %s", f, err) - } - if bytes.Contains(b, []byte("")) { - t.Errorf("File %s contains ", f) - } + require.NoError(t, err, "Unable to read file %s", f) + assert.Falsef(t, bytes.Contains(b, []byte("")), "File %s contains ", f) } } @@ -115,9 +98,8 @@ func TestCreate_Overwrite(t *testing.T) { var errlog bytes.Buffer - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err := Create("foo", tdir) + require.NoError(t, err) dir := filepath.Join(tdir, "foo") @@ -126,22 +108,13 @@ func TestCreate_Overwrite(t *testing.T) { // Now re-run the create Stderr = &errlog - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err = Create("foo", tdir) + require.NoError(t, err) data, err := os.ReadFile(tplname) - if err != nil { - t.Fatal(err) - } - - if string(data) == "FOO" { - t.Fatal("File that should have been modified was not.") - } - - if errlog.Len() == 0 { - t.Error("Expected warnings about overwriting files.") - } + require.NoError(t, err) + require.NotEqual(t, "FOO", string(data), "File that should have been modified was not.") + assert.NotEqual(t, 0, errlog.Len(), "Expected warnings about overwriting files.") } func TestValidateChartName(t *testing.T) { diff --git a/pkg/cmd/plugin_uninstall_test.go b/pkg/cmd/plugin_uninstall_test.go index f715b09c8..bd08f6f13 100644 --- a/pkg/cmd/plugin_uninstall_test.go +++ b/pkg/cmd/plugin_uninstall_test.go @@ -21,6 +21,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/cli" @@ -39,9 +42,7 @@ func TestPluginUninstallCleansUpVersionedFiles(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(pluginsDir, pluginName) - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create plugin.yaml pluginYAML := `name: test-plugin @@ -49,31 +50,21 @@ version: 1.2.3 description: Test plugin command: $HELM_PLUGIN_DIR/test-plugin ` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644)) // Create versioned tarball and provenance files tarballFile := filepath.Join(pluginsDir, "test-plugin-1.2.3.tgz") provFile := filepath.Join(pluginsDir, "test-plugin-1.2.3.tgz.prov") otherVersionTarball := filepath.Join(pluginsDir, "test-plugin-2.0.0.tgz") - if err := os.WriteFile(tarballFile, []byte("fake tarball"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(provFile, []byte("fake provenance"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tarballFile, []byte("fake tarball"), 0o644)) + require.NoError(t, os.WriteFile(provFile, []byte("fake provenance"), 0o644)) // Create another version that should NOT be removed - if err := os.WriteFile(otherVersionTarball, []byte("other version"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(otherVersionTarball, []byte("other version"), 0o644)) // Load the plugin p, err := plugin.LoadDir(pluginDir) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Create a test uninstall function that uses our test settings testUninstallPlugin := func(plugin plugin.Plugin) error { @@ -112,35 +103,26 @@ command: $HELM_PLUGIN_DIR/test-plugin } // Verify files exist before uninstall - if _, err := os.Stat(tarballFile); os.IsNotExist(err) { - t.Fatal("tarball file should exist before uninstall") - } - if _, err := os.Stat(provFile); os.IsNotExist(err) { - t.Fatal("provenance file should exist before uninstall") - } - if _, err := os.Stat(otherVersionTarball); os.IsNotExist(err) { - t.Fatal("other version tarball should exist before uninstall") - } + _, err = os.Stat(tarballFile) + require.False(t, os.IsNotExist(err), "tarball file should exist before uninstall") + _, err = os.Stat(provFile) + require.False(t, os.IsNotExist(err), "provenance file should exist before uninstall") + _, err = os.Stat(otherVersionTarball) + require.False(t, os.IsNotExist(err), "other version tarball should exist before uninstall") // Uninstall the plugin - if err := testUninstallPlugin(p); err != nil { - t.Fatal(err) - } + require.NoError(t, testUninstallPlugin(p)) // Verify plugin directory is removed - if _, err := os.Stat(pluginDir); !os.IsNotExist(err) { - t.Error("plugin directory should be removed") - } + _, err = os.Stat(pluginDir) + assert.True(t, os.IsNotExist(err), "plugin directory should be removed") // Verify only exact version files are removed - if _, err := os.Stat(tarballFile); !os.IsNotExist(err) { - t.Error("versioned tarball file should be removed") - } - if _, err := os.Stat(provFile); !os.IsNotExist(err) { - t.Error("versioned provenance file should be removed") - } + _, err = os.Stat(tarballFile) + assert.True(t, os.IsNotExist(err), "versioned tarball file should be removed") + _, err = os.Stat(provFile) + assert.True(t, os.IsNotExist(err), "versioned provenance file should be removed") // Verify other version files are NOT removed - if _, err := os.Stat(otherVersionTarball); os.IsNotExist(err) { - t.Error("other version tarball should NOT be removed") - } + _, err = os.Stat(otherVersionTarball) + assert.False(t, os.IsNotExist(err), "other version tarball should NOT be removed") } diff --git a/pkg/cmd/repo_remove_test.go b/pkg/cmd/repo_remove_test.go index 3b0072a68..7d252c35d 100644 --- a/pkg/cmd/repo_remove_test.go +++ b/pkg/cmd/repo_remove_test.go @@ -21,9 +21,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/repo/v1" "helm.sh/helm/v4/pkg/repo/v1/repotest" @@ -49,41 +51,29 @@ func TestRepoRemove(t *testing.T) { repoCache: rootDir, } - if err := rmOpts.run(os.Stderr); err == nil { - t.Errorf("Expected error removing %s, but did not get one.", testRepoName) - } + require.Errorf(t, rmOpts.run(os.Stderr), "Expected error removing %s, but did not get one.", testRepoName) o := &repoAddOptions{ name: testRepoName, url: ts.URL(), repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) cacheIndexFile, cacheChartsFile := createCacheFiles(rootDir, testRepoName) // Reset the buffer before running repo remove b.Reset() - if err := rmOpts.run(b); err != nil { - t.Errorf("Error removing %s from repositories", testRepoName) - } - if !strings.Contains(b.String(), "has been removed") { - t.Errorf("Unexpected output: %s", b.String()) - } + require.NoErrorf(t, rmOpts.run(b), "Error removing %s from repositories", testRepoName) + assert.Contains(t, b.String(), "has been removed", "Unexpected output: %s", b.String()) testCacheFiles(t, cacheIndexFile, cacheChartsFile, testRepoName) f, err := repo.LoadFile(repoFile) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if f.Has(testRepoName) { - t.Errorf("%s was not successfully removed from repositories list", testRepoName) - } + assert.Falsef(t, f.Has(testRepoName), "%s was not successfully removed from repositories list", testRepoName) // Test removal of multiple repos in one go var testRepoNames = []string{"foo", "bar", "baz"} @@ -97,9 +87,7 @@ func TestRepoRemove(t *testing.T) { repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) cacheIndex, cacheChart := createCacheFiles(rootDir, repoName) cacheFiles[repoName] = []string{cacheIndex, cacheChart} @@ -116,23 +104,15 @@ func TestRepoRemove(t *testing.T) { b.Reset() // Run repo remove command - if err := multiRmOpts.run(b); err != nil { - t.Errorf("Error removing list of repos from repositories: %q", testRepoNames) - } + require.NoErrorf(t, multiRmOpts.run(b), "Error removing list of repos from repositories: %q", testRepoNames) // Check that stuff were removed - if !strings.Contains(b.String(), "has been removed") { - t.Errorf("Unexpected output: %s", b.String()) - } + assert.Contains(t, b.String(), "has been removed", "Unexpected output: %s", b.String()) for _, repoName := range testRepoNames { f, err := repo.LoadFile(repoFile) - if err != nil { - t.Error(err) - } - if f.Has(repoName) { - t.Errorf("%s was not successfully removed from repositories list", repoName) - } + require.NoError(t, err) + assert.Falsef(t, f.Has(repoName), "%s was not successfully removed from repositories list", repoName) cacheIndex := cacheFiles[repoName][0] cacheChart := cacheFiles[repoName][1] testCacheFiles(t, cacheIndex, cacheChart, repoName) @@ -153,12 +133,10 @@ func createCacheFiles(rootDir string, repoName string) (cacheIndexFile string, c func testCacheFiles(t *testing.T, cacheIndexFile string, cacheChartsFile string, repoName string) { t.Helper() - if _, err := os.Stat(cacheIndexFile); err == nil { - t.Errorf("Error cache index file was not removed for repository %s", repoName) - } - if _, err := os.Stat(cacheChartsFile); err == nil { - t.Errorf("Error cache chart file was not removed for repository %s", repoName) - } + _, err := os.Stat(cacheIndexFile) + require.Errorf(t, err, "Error cache index file was not removed for repository %s", repoName) + _, err = os.Stat(cacheChartsFile) + assert.Errorf(t, err, "Error cache chart file was not removed for repository %s", repoName) } func TestRepoRemoveCompletion(t *testing.T) { @@ -183,9 +161,7 @@ func TestRepoRemoveCompletion(t *testing.T) { repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) } repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) diff --git a/pkg/cmd/repo_update_test.go b/pkg/cmd/repo_update_test.go index 7aa4d414f..ccd8b89c6 100644 --- a/pkg/cmd/repo_update_test.go +++ b/pkg/cmd/repo_update_test.go @@ -24,6 +24,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/repo/v1" @@ -44,9 +47,7 @@ func TestUpdateCmd(t *testing.T) { update: updater, repoFile: "testdata/repositories.yaml", } - if err := o.run(&out); err != nil { - t.Fatal(err) - } + require.NoError(t, o.run(&out)) if got := out.String(); !strings.Contains(got, "charts") || !strings.Contains(got, "firstexample") || @@ -70,9 +71,7 @@ func TestUpdateCmdMultiple(t *testing.T) { repoFile: "testdata/repositories.yaml", names: []string{"firstexample", "charts"}, } - if err := o.run(&out); err != nil { - t.Fatal(err) - } + require.NoError(t, o.run(&out)) if got := out.String(); !strings.Contains(got, "charts") || !strings.Contains(got, "firstexample") || @@ -96,9 +95,7 @@ func TestUpdateCmdInvalid(t *testing.T) { repoFile: "testdata/repositories.yaml", names: []string{"firstexample", "invalid"}, } - if err := o.run(&out); err == nil { - t.Fatal("expected error but did not get one") - } + require.Error(t, o.run(&out), "expected error but did not get one") } func TestUpdateCustomCacheCmd(t *testing.T) { @@ -119,12 +116,9 @@ func TestUpdateCustomCacheCmd(t *testing.T) { repoCache: cachePath, } b := io.Discard - if err := o.run(b); err != nil { - t.Fatal(err) - } - if _, err := os.Stat(filepath.Join(cachePath, "test-index.yaml")); err != nil { - t.Fatalf("error finding created index file in custom cache: %v", err) - } + require.NoError(t, o.run(b)) + _, err := os.Stat(filepath.Join(cachePath, "test-index.yaml")) + require.NoErrorf(t, err, "error finding created index file in custom cache") } func TestUpdateCharts(t *testing.T) { @@ -140,20 +134,14 @@ func TestUpdateCharts(t *testing.T) { Name: "charts", URL: ts.URL(), }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b := bytes.NewBuffer(nil) updateCharts([]*repo.ChartRepository{r}, b) got := b.String() - if strings.Contains(got, "Unable to get an update") { - t.Errorf("Failed to get a repo: %q", got) - } - if !strings.Contains(got, "Update Complete.") { - t.Error("Update was not successful") - } + assert.NotContains(t, got, "Unable to get an update", "Failed to get a repo: %q", got) + assert.Contains(t, got, "Update Complete.", "Update was not successful") } func TestRepoUpdateFileCompletion(t *testing.T) { @@ -176,37 +164,22 @@ func TestUpdateChartsFailWithError(t *testing.T) { Name: "charts", URL: invalidURL, }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) r2, err := repo.NewChartRepository(&repo.Entry{ Name: "charts", URL: invalidURL, }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b := bytes.NewBuffer(nil) err = updateCharts([]*repo.ChartRepository{r1, r2}, b) - if err == nil { - t.Error("Repo update should return error because update of repository fails and 'fail-on-repo-update-fail' flag set") - return - } + require.Error(t, err, "Repo update should return error because update of repository fails and 'fail-on-repo-update-fail' flag set") var expectedErr = "failed to update the following repositories" var receivedErr = err.Error() - if !strings.Contains(receivedErr, expectedErr) { - t.Errorf("Expected error (%s) but got (%s) instead", expectedErr, receivedErr) - } - if !strings.Contains(receivedErr, invalidURL) { - t.Errorf("Expected invalid URL (%s) in error message but got (%s) instead", invalidURL, receivedErr) - } + require.ErrorContains(t, err, expectedErr, "Expected error (%s) but got (%s) instead", expectedErr, receivedErr) + require.ErrorContains(t, err, invalidURL, "Expected invalid URL (%s) in error message but got (%s) instead", invalidURL, receivedErr) got := b.String() - if !strings.Contains(got, "Unable to get an update") { - t.Errorf("Repo should have failed update but instead got: %q", got) - } - if strings.Contains(got, "Update Complete.") { - t.Error("Update was not successful and should return error message because 'fail-on-repo-update-fail' flag set") - } + assert.Contains(t, got, "Unable to get an update", "Repo should have failed update but instead got: %q", got) + assert.NotContains(t, got, "Update Complete.", "Update was not successful and should return error message because 'fail-on-repo-update-fail' flag set") } diff --git a/pkg/kube/resource_test.go b/pkg/kube/resource_test.go index 283b44945..ca41a06ed 100644 --- a/pkg/kube/resource_test.go +++ b/pkg/kube/resource_test.go @@ -19,6 +19,7 @@ package kube import ( "testing" + "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/resource" @@ -37,27 +38,17 @@ func TestResourceList(t *testing.T) { r1 = []*resource.Info{info("foo"), info("bar")} r2 = []*resource.Info{info("bar")} - if r1.Get(info("bar")).Mapping.Resource.Resource != "pod" { - t.Error("expected get pod") - } + assert.Equal(t, "pod", r1.Get(info("bar")).Mapping.Resource.Resource, "expected get pod") diff := r1.Difference(r2) - if len(diff) != 1 { - t.Error("expected 1 result") - } + assert.Len(t, diff, 1, "expected 1 result") - if !diff.Contains(info("foo")) { - t.Error("expected diff to return foo") - } + assert.True(t, diff.Contains(info("foo")), "expected diff to return foo") inter := r1.Intersect(r2) - if len(inter) != 1 { - t.Error("expected 1 result") - } + assert.Len(t, inter, 1, "expected 1 result") - if !inter.Contains(info("bar")) { - t.Error("expected intersect to return bar") - } + assert.True(t, inter.Contains(info("bar")), "expected intersect to return bar") } func TestIsMatchingInfo(t *testing.T) { @@ -66,35 +57,23 @@ func TestIsMatchingInfo(t *testing.T) { gvkDiffGroup := schema.GroupVersionKind{Group: "diff", Version: "version1", Kind: "pod"} resourceInfoDiffGroup := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffGroup}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffGroup) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffGroup), "expected resources not equal") gvkDiffVersion := schema.GroupVersionKind{Group: "group1", Version: "diff", Kind: "pod"} resourceInfoDiffVersion := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffVersion}} - if !isMatchingInfo(&resourceInfo, &resourceInfoDiffVersion) { - t.Error("expected resources with different versions but same group and kind to be equal") - } + assert.True(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffVersion), "expected resources with different versions but same group and kind to be equal") gvkDiffKind := schema.GroupVersionKind{Group: "group1", Version: "version1", Kind: "deployment"} resourceInfoDiffKind := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffKind}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffKind) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffKind), "expected resources not equal") resourceInfoDiffName := resource.Info{Name: "diff", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvk}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffName) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffName), "expected resources not equal") resourceInfoDiffNamespace := resource.Info{Name: "name1", Namespace: "diff", Mapping: &meta.RESTMapping{GroupVersionKind: gvk}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffNamespace) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffNamespace), "expected resources not equal") gvkEqual := schema.GroupVersionKind{Group: "group1", Version: "version1", Kind: "pod"} resourceInfoEqual := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkEqual}} - if !isMatchingInfo(&resourceInfo, &resourceInfoEqual) { - t.Error("expected resources to be equal") - } + assert.True(t, isMatchingInfo(&resourceInfo, &resourceInfoEqual), "expected resources to be equal") } From 1d4665e54c28a41a5631c19f3bff14ef3d4e058f Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 111/161] chore(pkg): refactor: convert tests to testify assert/require part 20 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/chart/common/util/values_test.go | 52 ++++++-------- pkg/chart/loader/archive/archive_test.go | 29 +++----- pkg/chart/v2/lint/lint_test.go | 43 +++--------- pkg/cmd/list_test.go | 46 +++---------- pkg/cmd/package_test.go | 44 +++++------- pkg/cmd/release_testing_test.go | 12 ++-- pkg/cmd/source_date_epoch_test.go | 44 ++++-------- .../chart_downloader_windows_test.go | 67 +++++++++---------- pkg/kube/wait_test.go | 36 +++------- pkg/registry/client_tls_test.go | 23 +++---- pkg/release/v1/info_test.go | 43 +++++------- 11 files changed, 151 insertions(+), 288 deletions(-) diff --git a/pkg/chart/common/util/values_test.go b/pkg/chart/common/util/values_test.go index 1882fd0c4..e87a69237 100644 --- a/pkg/chart/common/util/values_test.go +++ b/pkg/chart/common/util/values_test.go @@ -20,6 +20,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" ) @@ -61,42 +64,26 @@ func TestToRenderValues(t *testing.T) { } res, err := ToRenderValuesWithSchemaValidation(c, overrideValues, o, nil, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Ensure that the top-level values are all set. metamap := res["Chart"].(map[string]any) - if name := metamap["Name"]; name.(string) != "test" { - t.Errorf("Expected chart name 'test', got %q", name) - } + name := metamap["Name"] + assert.Equalf(t, "test", name.(string), "Expected chart name 'test', got %q", name) relmap := res["Release"].(map[string]any) - if name := relmap["Name"]; name.(string) != "Seven Voyages" { - t.Errorf("Expected release name 'Seven Voyages', got %q", name) - } - if namespace := relmap["Namespace"]; namespace.(string) != "default" { - t.Errorf("Expected namespace 'default', got %q", namespace) - } - if revision := relmap["Revision"]; revision.(int) != 1 { - t.Errorf("Expected revision '1', got %d", revision) - } - if relmap["IsUpgrade"].(bool) { - t.Error("Expected upgrade to be false.") - } - if !relmap["IsInstall"].(bool) { - t.Error("Expected install to be true.") - } - if !res["Capabilities"].(*common.Capabilities).APIVersions.Has("v1") { - t.Error("Expected Capabilities to have v1 as an API") - } - if res["Capabilities"].(*common.Capabilities).KubeVersion.Major != "1" { - t.Error("Expected Capabilities to have a Kube version") - } + name = relmap["Name"] + assert.Equalf(t, "Seven Voyages", name.(string), "Expected release name 'Seven Voyages', got %q", name) + namespace := relmap["Namespace"] + assert.Equalf(t, "default", namespace.(string), "Expected namespace 'default', got %q", namespace) + revision := relmap["Revision"] + assert.Equalf(t, 1, revision.(int), "Expected revision '1', got %d", revision) + assert.False(t, relmap["IsUpgrade"].(bool), "Expected upgrade to be false.") + assert.True(t, relmap["IsInstall"].(bool), "Expected install to be true.") + assert.True(t, res["Capabilities"].(*common.Capabilities).APIVersions.Has("v1"), "Expected Capabilities to have v1 as an API") + assert.Equal(t, "1", res["Capabilities"].(*common.Capabilities).KubeVersion.Major, "Expected Capabilities to have a Kube version") vals := res["Values"].(common.Values) - if vals["name"] != "Haroun" { - t.Errorf("Expected 'Haroun', got %q (%v)", vals["name"], vals) - } + assert.Equal(t, "Haroun", vals["name"], "Expected 'Haroun', got %q (%v)", vals["name"], vals) where := vals["where"].(map[string]any) expects := map[string]string{ "city": "Baghdad", @@ -104,8 +91,7 @@ func TestToRenderValues(t *testing.T) { "title": "caliph", } for field, expect := range expects { - if got := where[field]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, where) - } + got := where[field] + assert.Equalf(t, got, expect, "Expected %q, got %q (%v)", expect, got, where) } } diff --git a/pkg/chart/loader/archive/archive_test.go b/pkg/chart/loader/archive/archive_test.go index 2fe09e9b2..3c3d336c3 100644 --- a/pkg/chart/loader/archive/archive_test.go +++ b/pkg/chart/loader/archive/archive_test.go @@ -21,6 +21,8 @@ import ( "bytes" "compress/gzip" "testing" + + "github.com/stretchr/testify/require" ) func TestLoadArchiveFiles(t *testing.T) { @@ -34,9 +36,7 @@ func TestLoadArchiveFiles(t *testing.T) { generate: func(_ *tar.Writer) {}, check: func(t *testing.T, _ []*BufferedFile, err error) { t.Helper() - if err.Error() != "no files in chart archive" { - t.Fatalf(`expected "no files in chart archive", got [%#v]`, err) - } + require.EqualError(t, err, "no files in chart archive") }, }, { @@ -44,32 +44,21 @@ func TestLoadArchiveFiles(t *testing.T) { generate: func(w *tar.Writer) { // simulate the presence of a `pax_global_header` file like you would get when // processing a GitHub release archive. - err := w.WriteHeader(&tar.Header{ + require.NoError(t, w.WriteHeader(&tar.Header{ Typeflag: tar.TypeXGlobalHeader, Name: "pax_global_header", - }) - if err != nil { - t.Fatal(err) - } + })) // we need to have at least one file, otherwise we'll get the "no files in chart archive" error - err = w.WriteHeader(&tar.Header{ + require.NoError(t, w.WriteHeader(&tar.Header{ Typeflag: tar.TypeReg, Name: "dir/empty", - }) - if err != nil { - t.Fatal(err) - } + })) }, check: func(t *testing.T, files []*BufferedFile, err error) { t.Helper() - if err != nil { - t.Fatalf(`got unwanted error [%#v] for tar file with pax_global_header content`, err) - } - - if len(files) != 1 { - t.Fatalf(`expected to get one file but got [%v]`, files) - } + require.NoErrorf(t, err, `got unwanted error for tar file with pax_global_header content`) + require.Lenf(t, files, 1, `expected to get one file but got [%v]`, files) }, }, } diff --git a/pkg/chart/v2/lint/lint_test.go b/pkg/chart/v2/lint/lint_test.go index 85960131b..1782c01d4 100644 --- a/pkg/chart/v2/lint/lint_test.go +++ b/pkg/chart/v2/lint/lint_test.go @@ -97,34 +97,22 @@ func TestBadChart(t *testing.T) { func TestInvalidYaml(t *testing.T) { var values map[string]any m := RunAll(badYamlFileDir, values, namespace).Messages - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "deliberateSyntaxError") { - t.Error("All didn't have the error for deliberateSyntaxError") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "deliberateSyntaxError", "All didn't have the error for deliberateSyntaxError") } func TestInvalidChartYaml(t *testing.T) { var values map[string]any m := RunAll(invalidChartFileDir, values, namespace).Messages - if len(m) != 2 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "failed to strictly parse chart metadata file") { - t.Error("All didn't have the error for duplicate YAML keys") - } + require.Len(t, m, 2, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "failed to strictly parse chart metadata file", "All didn't have the error for duplicate YAML keys") } func TestBadValues(t *testing.T) { var values map[string]any m := RunAll(badValuesFileDir, values, namespace).Messages - if len(m) < 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "unable to parse YAML") { - t.Errorf("All didn't have the error for invalid key format: %s", m[0].Err) - } + require.GreaterOrEqualf(t, len(m), 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "unable to parse YAML", "All didn't have the error for invalid key format: %s", m[0].Err) } func TestBadCrdFile(t *testing.T) { @@ -154,11 +142,7 @@ func TestHelmCreateChart(t *testing.T) { dir := t.TempDir() createdChart, err := chartutil.Create("testhelmcreatepasseslint", dir) - if err != nil { - t.Error(err) - // Fatal is bad because of the defer. - return - } + require.NoError(t, err) // Note: we test with strict=true here, even though others have // strict = false. @@ -182,10 +166,7 @@ func TestHelmCreateChart(t *testing.T) { // of the `--set` flag. func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { createdChart, err := chartutil.Create("checkdeprecatedwarnings", t.TempDir()) - if err != nil { - t.Error(err) - return - } + require.NoError(t, err) // Add values to enable hpa, and ingress which are disabled by default. // This is the equivalent of: @@ -238,11 +219,7 @@ func TestMalformedTemplate(t *testing.T) { case <-c: t.Fatal("lint malformed template timeout") case <-ch: - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "invalid character '{'") { - t.Error("All didn't have the error for invalid character '{'") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "invalid character '{'", "All didn't have the error for invalid character '{'") } } diff --git a/pkg/cmd/list_test.go b/pkg/cmd/list_test.go index f45616250..41426fedb 100644 --- a/pkg/cmd/list_test.go +++ b/pkg/cmd/list_test.go @@ -426,20 +426,9 @@ func TestReleaseListWriterMethods(t *testing.T) { var buf []byte out := &bytesWriter{buf: &buf} - err := writer.WriteJSON(out) - if err != nil { - t.Errorf("WriteJSON failed: %v", err) - } - - err = writer.WriteYAML(out) - if err != nil { - t.Errorf("WriteYAML failed: %v", err) - } - - err = writer.WriteTable(out) - if err != nil { - t.Errorf("WriteTable failed: %v", err) - } + require.NoError(t, writer.WriteJSON(out), "WriteJSON failed") + require.NoError(t, writer.WriteYAML(out), "WriteYAML failed") + assert.NoError(t, writer.WriteTable(out), "WriteTable failed") }) } @@ -448,20 +437,9 @@ func TestReleaseListWriterMethods(t *testing.T) { var buf []byte out := &bytesWriter{buf: &buf} - err := writer.WriteJSON(out) - if err != nil { - t.Errorf("WriteJSON failed: %v", err) - } - - err = writer.WriteYAML(out) - if err != nil { - t.Errorf("WriteYAML failed: %v", err) - } - - err = writer.WriteTable(out) - if err != nil { - t.Errorf("WriteTable failed: %v", err) - } + require.NoError(t, writer.WriteJSON(out), "WriteJSON failed") + require.NoError(t, writer.WriteYAML(out), "WriteYAML failed") + assert.NoError(t, writer.WriteTable(out), "WriteTable failed") } func TestFilterReleases(t *testing.T) { @@ -512,9 +490,7 @@ func TestFilterReleases(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := filterReleases(tt.releases, tt.ignoredReleaseNames) - if len(result) != tt.expectedCount { - t.Errorf("Expected %d releases, got %d", tt.expectedCount, len(result)) - } + assert.Len(t, result, tt.expectedCount, "Expected %d releases, got %d", tt.expectedCount, len(result)) }) } } @@ -603,13 +579,9 @@ func TestListStatusMapping(t *testing.T) { } writer := newReleaseListWriter(releaseFixture, "", false, false) - if len(writer.releases) != 1 { - t.Errorf("Expected 1 release, got %d", len(writer.releases)) - } + assert.Len(t, writer.releases, 1, "Expected 1 release, got %d", len(writer.releases)) - if writer.releases[0].Status != tc.status.String() { - t.Errorf("Expected status %s, got %s", tc.status.String(), writer.releases[0].Status) - } + assert.Equal(t, tc.status.String(), writer.releases[0].Status, "Expected status %s, got %s", tc.status.String(), writer.releases[0].Status) }) } } diff --git a/pkg/cmd/package_test.go b/pkg/cmd/package_test.go index 5705c9b9e..d78f5d88d 100644 --- a/pkg/cmd/package_test.go +++ b/pkg/cmd/package_test.go @@ -23,6 +23,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -105,18 +108,14 @@ func TestPackage(t *testing.T) { } origDir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Chdir(t.TempDir()) ensure.HelmHome(t) - if err := os.MkdirAll("toot", 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll("toot", 0o777)) // This is an unfortunate byproduct of the tmpdir if v, ok := tt.flags["keyring"]; ok && v != "" { @@ -140,6 +139,7 @@ func TestPackage(t *testing.T) { } } _, _, err = executeActionCommand(strings.Join(cmd, " ")) + if err != nil { if tt.err && re.MatchString(err.Error()) { return @@ -148,19 +148,15 @@ func TestPackage(t *testing.T) { } if tt.hasfile != "" { - if fi, err := os.Stat(tt.hasfile); err != nil { - t.Errorf("%q: expected file %q, got err %q", tt.name, tt.hasfile, err) - } else if fi.Size() == 0 { - t.Errorf("%q: file %q has zero bytes.", tt.name, tt.hasfile) - } + fi, err := os.Stat(tt.hasfile) + require.NoErrorf(t, err, "%q: expected file %q", tt.name, tt.hasfile) + assert.NotEqualf(t, 0, fi.Size(), "%q: file %q has zero bytes.", tt.name, tt.hasfile) } if v, ok := tt.flags["sign"]; ok && v == "1" { - if fi, err := os.Stat(tt.hasfile + ".prov"); err != nil { - t.Errorf("%q: expected provenance file", tt.name) - } else if fi.Size() == 0 { - t.Errorf("%q: provenance file is empty", tt.name) - } + fi, err := os.Stat(tt.hasfile + ".prov") + require.NoErrorf(t, err, "%q: expected provenance file", tt.name) + assert.NotEqualf(t, 0, fi.Size(), "%q: provenance file is empty", tt.name) } }) } @@ -178,18 +174,12 @@ func TestSetAppVersion(t *testing.T) { t.Fatal(err) } chartPath := filepath.Join(dir, "alpine-0.1.0.tgz") - if fi, err := os.Stat(chartPath); err != nil { - t.Errorf("expected file %q, got err %q", chartPath, err) - } else if fi.Size() == 0 { - t.Errorf("file %q has zero bytes.", chartPath) - } + fi, err := os.Stat(chartPath) + require.NoErrorf(t, err, "expected file %q", chartPath) + assert.NotEqualf(t, 0, fi.Size(), "file %q has zero bytes.", chartPath) ch, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("unexpected error loading packaged chart: %v", err) - } - if ch.Metadata.AppVersion != expectedAppVersion { - t.Errorf("expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion) - } + require.NoError(t, err, "unexpected error loading packaged chart") + assert.Equal(t, expectedAppVersion, ch.Metadata.AppVersion, "expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion) } func TestPackageFileCompletion(t *testing.T) { diff --git a/pkg/cmd/release_testing_test.go b/pkg/cmd/release_testing_test.go index fdb5df1e9..a39816843 100644 --- a/pkg/cmd/release_testing_test.go +++ b/pkg/cmd/release_testing_test.go @@ -19,9 +19,11 @@ package cmd import ( "bytes" "io" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -71,11 +73,7 @@ func TestReleaseTestNotesHandling(t *testing.T) { cmd1 := newReleaseTestCmd(actionConfig, &buf1) cmd1.SetArgs([]string{"test-release"}) err1 := cmd1.Execute() - if err1 != nil { - t.Fatalf("Unexpected error for default test: %v", err1) - } + require.NoError(t, err1, "Unexpected error for default test") output1 := buf1.String() - if strings.Contains(output1, "NOTES:") { - t.Errorf("Expected notes to be hidden by default, but found NOTES section in output: %s", output1) - } + assert.NotContains(t, output1, "NOTES:", "Expected notes to be hidden by default, but found NOTES section in output: %s", output1) } diff --git a/pkg/cmd/source_date_epoch_test.go b/pkg/cmd/source_date_epoch_test.go index 719de7c90..fa64c08b0 100644 --- a/pkg/cmd/source_date_epoch_test.go +++ b/pkg/cmd/source_date_epoch_test.go @@ -19,64 +19,48 @@ package cmd import ( "testing" "time" + + "github.com/stretchr/testify/require" ) func TestSourceDateEpochFromEnv(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "1609459200") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got == nil { - t.Fatal("expected non-nil epoch") - } + require.NoError(t, err, "sourceDateEpochFromEnv()") + require.NotNil(t, got, "expected non-nil epoch") want := time.Unix(1609459200, 0).UTC() - if !got.Equal(want) { - t.Fatalf("expected %v, got %v", want, *got) - } + require.Truef(t, got.Equal(want), "expected %v, got %v", want, *got) } func TestSourceDateEpochFromEnvUnset(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got != nil { - t.Fatalf("expected nil epoch, got %v", *got) - } + require.NoError(t, err, "sourceDateEpochFromEnv()") + require.Nil(t, got, "expected nil epoch") } func TestSourceDateEpochFromEnvInvalid(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "not-a-number") - if _, err := sourceDateEpochFromEnv(); err == nil { - t.Fatal("expected error for invalid SOURCE_DATE_EPOCH") - } + _, err := sourceDateEpochFromEnv() + require.Error(t, err, "expected error for invalid SOURCE_DATE_EPOCH") } func TestSourceDateEpochFromEnvNegative(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "-1") - if _, err := sourceDateEpochFromEnv(); err == nil { - t.Fatal("expected error for negative SOURCE_DATE_EPOCH") - } + _, err := sourceDateEpochFromEnv() + require.Error(t, err, "expected error for negative SOURCE_DATE_EPOCH") } func TestSourceDateEpochFromEnvZero(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "0") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got == nil { - t.Fatal("expected non-nil epoch") - } + require.NoError(t, err, "sourceDateEpochFromEnv() error") + require.NotNil(t, got, "expected non-nil epoch") want := time.Unix(0, 0).UTC() - if !got.Equal(want) { - t.Fatalf("expected %v, got %v", want, *got) - } + require.Truef(t, got.Equal(want), "expected %v, got %v", want, *got) } diff --git a/pkg/downloader/chart_downloader_windows_test.go b/pkg/downloader/chart_downloader_windows_test.go index 732416701..2b6bea5eb 100644 --- a/pkg/downloader/chart_downloader_windows_test.go +++ b/pkg/downloader/chart_downloader_windows_test.go @@ -23,6 +23,9 @@ import ( "sync" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/repo/v1/repotest" @@ -36,9 +39,7 @@ func TestParallelDownloadTo(t *testing.T) { srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/*.tgz")) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) dest := t.TempDir() cacheDir := t.TempDir() @@ -86,46 +87,38 @@ func TestParallelDownloadTo(t *testing.T) { } // With the file locking fix, all parallel downloads should succeed - if failedCount > 0 { - t.Errorf("Parallel downloads failed: %d out of %d downloads failed due to concurrent file access", failedCount, numDownloads) - } + assert.Falsef(t, failedCount > 0, "Parallel downloads failed: %d out of %d downloads failed due to concurrent file access", failedCount, numDownloads) // Verify the file exists and is valid expectedFile := filepath.Join(dest, "local-subchart-0.1.0.tgz") info, err := os.Stat(expectedFile) - if err != nil { - t.Errorf("Expected file %s does not exist: %v", expectedFile, err) - } else { - // Verify the file is not empty - if info.Size() == 0 { - t.Errorf("Downloaded file %s is empty (0 bytes)", expectedFile) - } - - // Verify the file has the expected size (should match the source file) - sourceFile := "testdata/local-subchart-0.1.0.tgz" - sourceInfo, err := os.Stat(sourceFile) - if err == nil && info.Size() != sourceInfo.Size() { - t.Errorf("Downloaded file size (%d bytes) doesn't match source file size (%d bytes)", - info.Size(), sourceInfo.Size()) - } + require.NoError(t, err, "Expected file %s does not exist: %v", expectedFile) + // Verify the file is not empty + assert.Falsef(t, info.Size() == 0, "Downloaded file %s is empty (0 bytes)", expectedFile) + + // Verify the file has the expected size (should match the source file) + sourceFile := "testdata/local-subchart-0.1.0.tgz" + sourceInfo, err := os.Stat(sourceFile) + if err == nil && info.Size() != sourceInfo.Size() { + t.Errorf("Downloaded file size (%d bytes) doesn't match source file size (%d bytes)", + info.Size(), sourceInfo.Size()) + } - // Verify it's a valid tar.gz file by checking the magic bytes - file, err := os.Open(expectedFile) - if err == nil { - defer file.Close() - // gzip magic bytes are 0x1f 0x8b - magic := make([]byte, 2) - if n, err := file.Read(magic); err == nil && n == 2 { - if magic[0] != 0x1f || magic[1] != 0x8b { - t.Errorf("Downloaded file is not a valid gzip file (magic bytes: %x)", magic) - } + // Verify it's a valid tar.gz file by checking the magic bytes + file, err := os.Open(expectedFile) + if err == nil { + defer file.Close() + // gzip magic bytes are 0x1f 0x8b + magic := make([]byte, 2) + if n, err := file.Read(magic); err == nil && n == 2 { + if magic[0] != 0x1f || magic[1] != 0x8b { + t.Errorf("Downloaded file is not a valid gzip file (magic bytes: %x)", magic) } } - - // Verify no lock file was left behind - lockFile := expectedFile + ".lock" - if _, err := os.Stat(lockFile); err == nil { - t.Errorf("Lock file %s was not cleaned up", lockFile) - } } + + // Verify no lock file was left behind + lockFile := expectedFile + ".lock" + _, err = os.Stat(lockFile) + assert.Falsef(t, err == nil, "Lock file %s was not cleaned up", lockFile) } diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go index acdfffa23..9cf1e5506 100644 --- a/pkg/kube/wait_test.go +++ b/pkg/kube/wait_test.go @@ -19,7 +19,6 @@ package kube import ( "errors" "net/http" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -298,17 +297,12 @@ func TestLegacyWaiter_waitForPodSuccess(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForPodSuccess(tt.obj, "foo") if tt.wantErr { - if err == nil { - t.Error("expected error, got none") - } else if !strings.Contains(err.Error(), tt.errMessage) { - t.Errorf("expected error to contain %q, got %q", tt.errMessage, err.Error()) - } - } else if err != nil { - t.Errorf("unexpected error: %v", err) - } - if done != tt.wantDone { - t.Errorf("got done=%v, want %v", done, tt.wantDone) + require.Error(t, err, "expected error, got none") + require.ErrorContains(t, err, tt.errMessage, "expected error to contain %q, got %q", tt.errMessage, err.Error()) + } else { + require.NoError(t, err) } + assert.Equal(t, tt.wantDone, done, "got done=%v, want %v", done, tt.wantDone) }) } } @@ -390,17 +384,11 @@ func TestLegacyWaiter_waitForJob(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForJob(tt.obj, "test-job") if tt.wantErr { - if err == nil { - t.Error("expected error, got none") - } else if !strings.Contains(err.Error(), tt.errMessage) { - t.Errorf("expected error to contain %q, got %q", tt.errMessage, err.Error()) - } - } else if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if done != tt.wantDone { - t.Errorf("got done=%v, want %v", done, tt.wantDone) + require.Error(t, err, "expected error, got none") + require.ErrorContainsf(t, err, tt.errMessage, "expected error to contain %q, got %q", tt.errMessage, err.Error()) + } else { + require.NoError(t, err) + assert.Equal(t, tt.wantDone, done, "got done=%v, want %v", done, tt.wantDone) } }) } @@ -459,9 +447,7 @@ func TestLegacyWaiter_isRetryableError(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := lw.isRetryableError(tt.err, info) - if got != tt.wantRetry { - t.Errorf("isRetryableError() = %v, want %v", got, tt.wantRetry) - } + assert.Equal(t, tt.wantRetry, got, "isRetryableError() = %v, want %v", got, tt.wantRetry) }) } } diff --git a/pkg/registry/client_tls_test.go b/pkg/registry/client_tls_test.go index 45eff232c..0bad5df64 100644 --- a/pkg/registry/client_tls_test.go +++ b/pkg/registry/client_tls_test.go @@ -40,22 +40,19 @@ func (suite *TLSRegistryClientTestSuite) TearDownSuite() { } func (suite *TLSRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)), "no error logging into registry with good credentials") } func (suite *TLSRegistryClientTestSuite) Test_1_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptTLSClientConfigFromConfig(&tls.Config{})) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptTLSClientConfigFromConfig(&tls.Config{})), "error logging into registry with bad credentials") // Create a *tls.Config from tlsCert, tlsKey, and tlsCA. cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey) @@ -69,10 +66,9 @@ func (suite *TLSRegistryClientTestSuite) Test_1_Login() { RootCAs: rootCAs, } - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptTLSClientConfigFromConfig(conf)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptTLSClientConfigFromConfig(conf)), "no error logging into registry with good credentials") } func (suite *TLSRegistryClientTestSuite) Test_1_Push() { @@ -94,8 +90,7 @@ func (suite *TLSRegistryClientTestSuite) Test_4_Logout() { suite.Require().Error(err, "failed to delete the credential for this-host-aint-real:5000") } - err = suite.RegistryClient.Logout(suite.DockerRegistryHost) - suite.Require().NoError(err, "no error logging out of registry") + suite.Require().NoError(suite.RegistryClient.Logout(suite.DockerRegistryHost), "no error logging out of registry") } func TestTLSRegistryClientTestSuite(t *testing.T) { diff --git a/pkg/release/v1/info_test.go b/pkg/release/v1/info_test.go index 12b3014f6..61a888cb8 100644 --- a/pkg/release/v1/info_test.go +++ b/pkg/release/v1/info_test.go @@ -253,17 +253,17 @@ func TestInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) + assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) + assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) + assert.Equal(t, tt.expected.Description, info.Description) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Notes, info.Notes) + assert.Equal(t, tt.expected.Resources, info.Resources) } - require.NoError(t, err) - assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) - assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) - assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) - assert.Equal(t, tt.expected.Description, info.Description) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Notes, info.Notes) - assert.Equal(t, tt.expected.Resources, info.Resources) }) } } @@ -284,9 +284,7 @@ func TestInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, original.LastDeployed.Unix(), decoded.LastDeployed.Unix()) assert.Equal(t, original.Deleted.Unix(), decoded.Deleted.Unix()) @@ -330,9 +328,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, tt.info.RollbackRevision, decoded.RollbackRevision) assert.Equal(t, tt.info.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, tt.info.LastDeployed.Unix(), decoded.LastDeployed.Unix()) @@ -342,8 +338,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { // Verify omitempty behavior: zero rollback_revision should not appear in JSON if tt.info.RollbackRevision == 0 { var raw map[string]any - err = json.Unmarshal(data, &raw) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &raw)) assert.NotContains(t, raw, "rollback_revision") } }) @@ -356,13 +351,12 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { input := `{"first_deployed":"","last_deployed":"","deleted":"","status":"deployed","description":"test"}` var info Info - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time fields are zero values - assert.True(t, info.FirstDeployed.IsZero()) - assert.True(t, info.LastDeployed.IsZero()) - assert.True(t, info.Deleted.IsZero()) + assert.Zero(t, info.FirstDeployed) + assert.Zero(t, info.LastDeployed) + assert.Zero(t, info.Deleted) assert.Equal(t, common.StatusDeployed, info.Status) assert.Equal(t, "test", info.Description) @@ -371,8 +365,7 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted due to omitzero tag assert.NotContains(t, result, "first_deployed") From a934b827fa9569c8769c981b1d4847f72a4c1f94 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 112/161] chore(pkg): refactor: convert tests to testify assert/require part 21 #### Description refactor: convert tests to testify assert/require in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/action/action_test.go | 20 ++++---------- pkg/action/dependency_test.go | 24 +++++------------ pkg/action/list_test.go | 29 +++++++------------- pkg/chart/v2/lint/support/message_test.go | 29 +++++++------------- pkg/cmd/history_test.go | 30 +++++++++------------ pkg/cmd/require/args_test.go | 16 ++++-------- pkg/cmd/rollback_test.go | 26 +++++++----------- pkg/cmd/root_test.go | 32 ++++++++--------------- pkg/cmd/search_hub_test.go | 28 +++++++------------- pkg/engine/files_test.go | 14 ++++------ pkg/engine/funcs_test.go | 12 +++------ pkg/getter/plugingetter_test.go | 23 ++++++---------- pkg/pusher/pusher_test.go | 31 +++++++++------------- pkg/registry/client_insecure_tls_test.go | 13 ++++----- pkg/release/v1/hook_test.go | 24 +++++++---------- pkg/storage/driver/mock_test.go | 18 ++++--------- pkg/storage/driver/util_test.go | 22 +++++++--------- 17 files changed, 138 insertions(+), 253 deletions(-) diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 880a9930b..056c539a5 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -58,9 +58,7 @@ func actionConfigFixtureWithDummyResources(t *testing.T, dummyResources kube.Res slog.SetDefault(logger) registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return &Configuration{ Releases: storage.Init(driver.NewMemory()), @@ -371,16 +369,10 @@ func TestGetVersionSet(t *testing.T) { client := fakeclientset.NewClientset() vs, err := GetVersionSet(client.Discovery()) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if !vs.Has("v1") { - t.Error("Expected supported versions to at least include v1.") - } - if vs.Has("nosuchversion/v1") { - t.Error("Non-existent version is reported found.") - } + assert.True(t, vs.Has("v1"), "Expected supported versions to at least include v1.") + assert.False(t, vs.Has("nosuchversion/v1"), "Non-existent version is reported found.") } // Mock PostRenderer for testing @@ -2031,9 +2023,7 @@ spec: mockPR := &mockPostRenderer{ transform: func(content string) string { count := strings.Count(content, "kind: ServiceAccount") - if count > 1 { - t.Errorf("post-renderer received %d ServiceAccount resources in a single stream, expected at most 1", count) - } + assert.LessOrEqualf(t, count, 1, "post-renderer received %d ServiceAccount resources in a single stream, expected at most 1", count) return content }, } diff --git a/pkg/action/dependency_test.go b/pkg/action/dependency_test.go index 25664b98c..adbe311d6 100644 --- a/pkg/action/dependency_test.go +++ b/pkg/action/dependency_test.go @@ -57,9 +57,7 @@ func TestList(t *testing.T) { }, } { buf := bytes.Buffer{} - if err := NewDependency().List(tcase.chart, &buf); err != nil { - t.Fatal(err) - } + require.NoError(t, NewDependency().List(tcase.chart, &buf)) test.AssertGoldenString(t, buf.String(), tcase.golden) } } @@ -71,22 +69,16 @@ func TestDependencyStatus_Dashes(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0o700); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(chartpath, 0o700)) // Add some fake charts first := buildChart(withName("first-chart")) _, err := chartutil.Save(first, chartpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) second := buildChart(withName("first-chart-second-chart")) _, err = chartutil.Save(second, chartpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dep := &chart.Dependency{ Name: "first-chart", @@ -95,9 +87,7 @@ func TestDependencyStatus_Dashes(t *testing.T) { // Now try to get the deps stat := NewDependency().dependencyStatus(dir, dep, first) - if stat != "ok" { - t.Errorf("Unexpected status: %q", stat) - } + assert.Equal(t, "ok", stat, "Unexpected status: %q", stat) } func TestStatArchiveForStatus(t *testing.T) { @@ -105,9 +95,7 @@ func TestStatArchiveForStatus(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0o700); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(chartpath, 0o700)) // unsaved chart lilith := buildChart(withName("lilith")) diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index e7c2770d7..1c849028d 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -44,9 +44,7 @@ func TestListStates(t *testing.T) { "unknown": ListUnknown, "totally made up key": ListUnknown, } { - if expect != expect.FromName(input) { - t.Errorf("Expected %d for %s", expect, input) - } + assert.Equal(t, expect.FromName(input), expect, "Expected %d for %s", expect, input) // This is a cheap way to verify that ListAll actually allows everything but Unknown if got := expect.FromName(input); got != ListUnknown && got&ListAll == 0 { t.Errorf("Expected %s to match the ListAll filter", input) @@ -54,12 +52,10 @@ func TestListStates(t *testing.T) { } filter := ListDeployed | ListPendingRollback - if status := filter.FromName("deployed"); filter&status == 0 { - t.Errorf("Expected %d to match mask %d", status, filter) - } - if status := filter.FromName("failed"); filter&status != 0 { - t.Errorf("Expected %d to fail to match mask %d", status, filter) - } + status := filter.FromName("deployed") + assert.NotEqualf(t, ListStates(0), filter&status, "Expected %d to match mask %d", status, filter) + status = filter.FromName("failed") + assert.Equalf(t, ListStates(0), filter&status, "Expected %d to fail to match mask %d", status, filter) } func TestList_Empty(t *testing.T) { @@ -202,8 +198,7 @@ func TestList_StateMask(t *testing.T) { } one.SetStatus(common.StatusUninstalled, "uninstalled") - err = lister.cfg.Releases.Update(one) - req.NoError(err) + req.NoError(lister.cfg.Releases.Update(one)) res, err := lister.Run() req.NoError(err) @@ -277,9 +272,7 @@ func makeMeSomeReleasesWithStaleFailure(t *testing.T, store *storage.Storage) { five.Version = 1 for _, rel := range []*release.Release{one, two, three, four, five} { - if err := store.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, store.Create(rel)) } all, err := store.ListReleases() @@ -328,9 +321,7 @@ func makeMeSomeReleases(t *testing.T, store *storage.Storage) { three.Version = 3 for _, rel := range []*release.Release{one, two, three} { - if err := store.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, store.Create(rel)) } all, err := store.ListReleases() @@ -389,9 +380,7 @@ func TestSelectorList(t *testing.T) { lister := newListFixture(t) for _, rel := range []*release.Release{r1, r2, r3} { - if err := lister.cfg.Releases.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, lister.cfg.Releases.Create(rel)) } t.Run("should fail selector parsing", func(t *testing.T) { diff --git a/pkg/chart/v2/lint/support/message_test.go b/pkg/chart/v2/lint/support/message_test.go index ce5b5e42e..dfbc65844 100644 --- a/pkg/chart/v2/lint/support/message_test.go +++ b/pkg/chart/v2/lint/support/message_test.go @@ -19,6 +19,9 @@ package support import ( "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var errLint = errors.New("lint failed") @@ -47,33 +50,19 @@ func TestRunLinterRule(t *testing.T) { linter := Linter{} for _, test := range tests { isValid := linter.RunLinterRule(test.Severity, "chart", test.LintError) - if len(linter.Messages) != test.ExpectedMessages { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) - } - - if linter.HighestSeverity != test.ExpectedHighestSeverity { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) - } - - if isValid != test.ExpectedReturn { - t.Errorf("RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) - } + assert.Lenf(t, linter.Messages, test.ExpectedMessages, "RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) + assert.Equalf(t, linter.HighestSeverity, test.ExpectedHighestSeverity, "RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) + assert.Equalf(t, isValid, test.ExpectedReturn, "RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) } } func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - if m.Error() != "[ERROR] Chart.yaml: Foo" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualErrorf(t, m, "[ERROR] Chart.yaml: Foo", "Unexpected output: %s", m.Error()) m = Message{WarningSev, "templates/", errors.New("Bar")} - if m.Error() != "[WARNING] templates/: Bar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualErrorf(t, m, "[WARNING] templates/: Bar", "Unexpected output: %s", m.Error()) m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - if m.Error() != "[INFO] templates/rc.yaml: FooBar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + assert.EqualErrorf(t, m, "[INFO] templates/rc.yaml: FooBar", "Unexpected output: %s", m.Error()) } diff --git a/pkg/cmd/history_test.go b/pkg/cmd/history_test.go index 2bace98e0..cd8e353e7 100644 --- a/pkg/cmd/history_test.go +++ b/pkg/cmd/history_test.go @@ -385,16 +385,16 @@ func TestReleaseInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.Revision, info.Revision) + assert.Equal(t, tt.expected.Updated.Unix(), info.Updated.Unix()) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.Chart, info.Chart) + assert.Equal(t, tt.expected.AppVersion, info.AppVersion) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Description, info.Description) } - require.NoError(t, err) - assert.Equal(t, tt.expected.Revision, info.Revision) - assert.Equal(t, tt.expected.Updated.Unix(), info.Updated.Unix()) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.Chart, info.Chart) - assert.Equal(t, tt.expected.AppVersion, info.AppVersion) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Description, info.Description) }) } } @@ -415,9 +415,7 @@ func TestReleaseInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded releaseInfo - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.Revision, decoded.Revision) assert.Equal(t, original.Updated.Unix(), decoded.Updated.Unix()) assert.Equal(t, original.Status, decoded.Status) @@ -433,11 +431,10 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { input := `{"revision":1,"updated":"","status":"deployed","chart":"mychart-1.0.0","app_version":"1.0.0","description":"Test"}` var info releaseInfo - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time field is zero value - assert.True(t, info.Updated.IsZero()) + assert.Zero(t, info.Updated) assert.Equal(t, 1, info.Revision) assert.Equal(t, "deployed", info.Status) @@ -446,8 +443,7 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time value should be omitted assert.NotContains(t, result, "updated") diff --git a/pkg/cmd/require/args_test.go b/pkg/cmd/require/args_test.go index 89403140e..5d3a9f003 100644 --- a/pkg/cmd/require/args_test.go +++ b/pkg/cmd/require/args_test.go @@ -18,10 +18,10 @@ package require import ( "io" "strconv" - "strings" "testing" "github.com/spf13/cobra" + "github.com/stretchr/testify/require" ) func TestArgs(t *testing.T) { @@ -77,16 +77,10 @@ func runTestCases(t *testing.T, testCases []testCase) { err := cmd.Execute() if tc.wantError == "" { - if err != nil { - t.Fatalf("unexpected error, got '%v'", err) - } - return - } - if !strings.Contains(err.Error(), tc.wantError) { - t.Fatalf("unexpected error \n\nWANT:\n%q\n\nGOT:\n%q\n", tc.wantError, err) - } - if !strings.Contains(err.Error(), "Usage:") { - t.Fatalf("unexpected error: want Usage string\n\nGOT:\n%q\n", err) + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.wantError) + require.ErrorContains(t, err, "Usage:") } }) } diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 116e158fd..ff7f314c9 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -21,6 +21,9 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" @@ -148,24 +151,15 @@ func TestRollbackWithLabels(t *testing.T) { } storage := storageFixture() for _, rel := range rels { - if err := storage.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, storage.Create(rel)) } _, _, err := executeActionCommandC(storage, fmt.Sprintf("rollback %s 1", releaseName)) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) + updatedReli, err := storage.Get(releaseName, 3) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !reflect.DeepEqual(updatedRel.Labels, labels1) { - t.Errorf("Expected {%v}, got {%v}", labels1, updatedRel.Labels) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Truef(t, reflect.DeepEqual(updatedRel.Labels, labels1), "Expected {%v}, got {%v}", labels1, updatedRel.Labels) } diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go index 316e6bd2e..b07bdbbf6 100644 --- a/pkg/cmd/root_test.go +++ b/pkg/cmd/root_test.go @@ -23,6 +23,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/helmpath" @@ -86,9 +89,8 @@ func TestRootCmd(t *testing.T) { t.Setenv(k, v) } - if _, _, err := executeActionCommand(tt.args); err != nil { - t.Fatalf("unexpected error: %s", err) - } + _, _, err := executeActionCommand(tt.args) + require.NoError(t, err) // NOTE(bacongobbler): we need to check here after calling ensure.HelmHome so we // load the proper paths after XDG_*_HOME is set @@ -104,15 +106,9 @@ func TestRootCmd(t *testing.T) { tt.dataPath = filepath.Join(os.Getenv(xdg.DataHomeEnvVar), "helm") } - if helmpath.CachePath() != tt.cachePath { - t.Errorf("expected cache path %q, got %q", tt.cachePath, helmpath.CachePath()) - } - if helmpath.ConfigPath() != tt.configPath { - t.Errorf("expected config path %q, got %q", tt.configPath, helmpath.ConfigPath()) - } - if helmpath.DataPath() != tt.dataPath { - t.Errorf("expected data path %q, got %q", tt.dataPath, helmpath.DataPath()) - } + assert.Equal(t, tt.cachePath, helmpath.CachePath(), "expected cache path %q, got %q", tt.cachePath, helmpath.CachePath()) + assert.Equal(t, tt.configPath, helmpath.ConfigPath(), "expected config path %q, got %q", tt.configPath, helmpath.ConfigPath()) + assert.Equal(t, tt.dataPath, helmpath.DataPath(), "expected data path %q, got %q", tt.dataPath, helmpath.DataPath()) }) } } @@ -120,9 +116,7 @@ func TestRootCmd(t *testing.T) { func TestUnknownSubCmd(t *testing.T) { _, _, err := executeActionCommand("foobar") - if err == nil || err.Error() != `unknown command "foobar" for "helm"` { - t.Errorf("Expect unknown command error, got %q", err) - } + assert.EqualErrorf(t, err, `unknown command "foobar" for "helm"`, "Expect unknown command error") } // Need the release of Cobra following 1.0 to be able to disable @@ -138,14 +132,10 @@ func TestRootCmdLogger(t *testing.T) { buf := new(bytes.Buffer) actionConfig := action.NewConfiguration() _, err := newRootCmdWithConfig(actionConfig, buf, args, SetupLogging) - if err != nil { - t.Errorf("expected no error, got: '%v'", err) - } + require.NoError(t, err) l1 := actionConfig.Logger() l2 := slog.Default() - if l1.Handler() != l2.Handler() { - t.Error("expected actionConfig logger to be the slog default logger") - } + assert.Equal(t, l2.Handler(), l1.Handler(), "expected actionConfig logger to be the slog default logger") } diff --git a/pkg/cmd/search_hub_test.go b/pkg/cmd/search_hub_test.go index 98bf052f2..7b00cc295 100644 --- a/pkg/cmd/search_hub_test.go +++ b/pkg/cmd/search_hub_test.go @@ -21,6 +21,9 @@ import ( "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSearchHubCmd(t *testing.T) { @@ -42,9 +45,7 @@ func TestSearchHubCmd(t *testing.T) { testcmd := "search hub --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } + require.NoError(t, err) if out != expected { t.Error("expected and actual output did not match") t.Log(out) @@ -71,9 +72,7 @@ func TestSearchHubListRepoCmd(t *testing.T) { testcmd := "search hub --list-repo-url --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } + require.NoError(t, err) if out != expected { t.Error("expected and actual output did not match") t.Log(out) @@ -165,21 +164,14 @@ func TestSearchHubCmd_FailOnNoResponseTests(t *testing.T) { _, out, err := executeActionCommandC(storage, tt.cmd) if tt.wantErr { - if err == nil { - t.Error("expected error due to no record in response, got nil") - } + require.Error(t, err, "expected error due to no record in response, got nil") } else { - if err != nil { - t.Errorf("unexpected error, got %q", err) - } + require.NoError(t, err) } - if out != tt.expected { - t.Errorf("expected and actual output did not match\n"+ - "expected: %q\n"+ - "actual : %q", - tt.expected, out) - } + assert.Equal(t, tt.expected, out, "expected and actual output did not match\n"+ + "expected: %q\n"+ + "actual : %q", tt.expected, out) }) } } diff --git a/pkg/engine/files_test.go b/pkg/engine/files_test.go index b4318a597..6ff251aad 100644 --- a/pkg/engine/files_test.go +++ b/pkg/engine/files_test.go @@ -44,17 +44,13 @@ func getTestFiles() files { func TestNewFiles(t *testing.T) { files := getTestFiles() - if len(files) != len(cases) { - t.Errorf("Expected len() = %d, got %d", len(cases), len(files)) - } + assert.Len(t, files, len(cases), "Expected len() = %d, got %d", len(cases), len(files)) for i, f := range cases { - if got := string(files.GetBytes(f.path)); got != f.data { - t.Errorf("%d: expected %q, got %q", i, f.data, got) - } - if got := files.Get(f.path); got != f.data { - t.Errorf("%d: expected %q, got %q", i, f.data, got) - } + got := string(files.GetBytes(f.path)) + assert.Equalf(t, got, f.data, "%d: expected %q, got %q", i, f.data, got) + got = files.Get(f.path) + assert.Equalf(t, got, f.data, "%d: expected %q, got %q", i, f.data, got) } } diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index bc541339b..beb87b429 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -134,8 +134,7 @@ keyInElement1 = "valueInElement1"`, for _, tt := range tests { var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) - require.NoError(t, err) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars)) assert.Equal(t, tt.expect, b.String(), tt.tpl) } @@ -360,8 +359,7 @@ func TestDurationHelpers(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) - require.NoError(t, err, tt.tpl) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars), tt.tpl) assert.Equal(t, tt.expect, b.String(), tt.tpl) }) } @@ -422,8 +420,7 @@ func TestDurationHelpers(t *testing.T) { Funcs(funcMap()). Parse(tt.tpl), ) - err := tmpl.Execute(&b, tt.vars) - require.Error(t, err, tt.tpl) + require.Error(t, tmpl.Execute(&b, tt.vars), tt.tpl) }) } } @@ -474,8 +471,7 @@ func TestMerge(t *testing.T) { } tpl := `{{merge .dst .src1 .src2}}` var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tpl)).Execute(&b, dict) - require.NoError(t, err) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tpl)).Execute(&b, dict)) expected := map[string]any{ "a": "one", // key overridden diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index 16af9eb31..c9ed9f779 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -35,25 +35,18 @@ func TestCollectPlugins(t *testing.T) { env.PluginsDirectory = pluginDir p, err := collectGetterPlugins(env) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(p) != 2 { - t.Errorf("Expected 2 plugins, got %d: %v", len(p), p) - } + assert.Len(t, p, 2, "Expected 2 plugins, got %d: %v", len(p), p) - if _, err := p.ByScheme("test2"); err != nil { - t.Error(err) - } + _, err = p.ByScheme("test2") + require.NoError(t, err) - if _, err := p.ByScheme("test"); err != nil { - t.Error(err) - } + _, err = p.ByScheme("test") + require.NoError(t, err) - if _, err := p.ByScheme("nosuchthing"); err == nil { - t.Fatal("did not expect protocol handler for nosuchthing") - } + _, err = p.ByScheme("nosuchthing") + require.Error(t, err, "did not expect protocol handler for nosuchthing") } func TestConvertOptions(t *testing.T) { diff --git a/pkg/pusher/pusher_test.go b/pkg/pusher/pusher_test.go index 71fab8694..078b2fa73 100644 --- a/pkg/pusher/pusher_test.go +++ b/pkg/pusher/pusher_test.go @@ -18,6 +18,9 @@ package pusher import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/registry" ) @@ -28,9 +31,7 @@ func TestProvider(t *testing.T) { func(_ ...Option) (Pusher, error) { return nil, nil }, } - if !p.Provides("three") { - t.Error("Expected provider to provide three") - } + assert.True(t, p.Provides("three"), "Expected provider to provide three") } func TestProviders(t *testing.T) { @@ -39,30 +40,24 @@ func TestProviders(t *testing.T) { {[]string{"two", "four"}, func(_ ...Option) (Pusher, error) { return nil, nil }}, } - if _, err := ps.ByScheme("one"); err != nil { - t.Error(err) - } - if _, err := ps.ByScheme("four"); err != nil { - t.Error(err) - } + _, err := ps.ByScheme("one") + require.NoError(t, err) + _, err = ps.ByScheme("four") + require.NoError(t, err) - if _, err := ps.ByScheme("five"); err == nil { - t.Error("Did not expect handler for five") - } + _, err = ps.ByScheme("five") + assert.Error(t, err, "Did not expect handler for five") } func TestAll(t *testing.T) { env := cli.New() all := All(env) - if len(all) != 1 { - t.Errorf("expected 1 provider (OCI), got %d", len(all)) - } + assert.Len(t, all, 1, "expected 1 provider (OCI), got %d", len(all)) } func TestByScheme(t *testing.T) { env := cli.New() g := All(env) - if _, err := g.ByScheme(registry.OCIScheme); err != nil { - t.Error(err) - } + _, err := g.ByScheme(registry.OCIScheme) + assert.NoError(t, err) } diff --git a/pkg/registry/client_insecure_tls_test.go b/pkg/registry/client_insecure_tls_test.go index ae0a44337..f1ece1b1c 100644 --- a/pkg/registry/client_insecure_tls_test.go +++ b/pkg/registry/client_insecure_tls_test.go @@ -38,15 +38,13 @@ func (suite *InsecureTLSRegistryClientTestSuite) TearDownSuite() { } func (suite *InsecureTLSRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptInsecure(true)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptInsecure(true)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(true)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptInsecure(true)), "no error logging into registry with good credentials") } func (suite *InsecureTLSRegistryClientTestSuite) Test_1_Push() { @@ -68,8 +66,7 @@ func (suite *InsecureTLSRegistryClientTestSuite) Test_4_Logout() { suite.Require().Error(err, "failed to delete the credential for this-host-aint-real:5000") } - err = suite.RegistryClient.Logout(suite.DockerRegistryHost) - suite.Require().NoError(err, "no error logging out of registry") + suite.Require().NoError(suite.RegistryClient.Logout(suite.DockerRegistryHost), "no error logging out of registry") } func TestInsecureTLSRegistryClientTestSuite(t *testing.T) { diff --git a/pkg/release/v1/hook_test.go b/pkg/release/v1/hook_test.go index f3b8811a6..9e803a0fc 100644 --- a/pkg/release/v1/hook_test.go +++ b/pkg/release/v1/hook_test.go @@ -170,12 +170,12 @@ func TestHookExecutionUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &exec) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) + assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) + assert.Equal(t, tt.expected.Phase, exec.Phase) } - require.NoError(t, err) - assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) - assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) - assert.Equal(t, tt.expected.Phase, exec.Phase) }) } } @@ -194,9 +194,7 @@ func TestHookExecutionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded HookExecution - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.StartedAt.Unix(), decoded.StartedAt.Unix()) assert.Equal(t, original.CompletedAt.Unix(), decoded.CompletedAt.Unix()) assert.Equal(t, original.Phase, decoded.Phase) @@ -208,12 +206,11 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { input := `{"started_at":"","completed_at":"","phase":"Succeeded"}` var exec HookExecution - err := json.Unmarshal([]byte(input), &exec) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &exec)) // Verify time fields are zero values - assert.True(t, exec.StartedAt.IsZero()) - assert.True(t, exec.CompletedAt.IsZero()) + assert.Zero(t, exec.StartedAt) + assert.Zero(t, exec.CompletedAt) assert.Equal(t, HookPhaseSucceeded, exec.Phase) // Marshal back and verify empty time fields are omitted @@ -221,8 +218,7 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted assert.NotContains(t, result, "started_at") diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index ab7b261cf..c366d106d 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -24,6 +24,7 @@ import ( sqlmock "github.com/DATA-DOG/go-sqlmock" sq "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -74,10 +75,7 @@ func tsFixtureMemory(t *testing.T) *Memory { mem := NewMemory() for _, tt := range hs { - err := mem.Create(testKey(tt.Name, tt.Version), tt) - if err != nil { - t.Fatalf("Test setup failed to create: %s\n", err) - } + require.NoError(t, mem.Create(testKey(tt.Name, tt.Version), tt), "Test setup failed to create") } return mem } @@ -108,9 +106,7 @@ func (mock *MockConfigMapsInterface) Init(t *testing.T, releases ...*rspb.Releas objkey := testKey(rls.Name, rls.Version) cfgmap, err := newConfigMapsObject(objkey, rls, nil) - if err != nil { - t.Fatalf("Failed to create configmap: %s", err) - } + require.NoError(t, err, "Failed to create configmap") mock.objects[objkey] = cfgmap } } @@ -196,9 +192,7 @@ func (mock *MockSecretsInterface) Init(t *testing.T, releases ...*rspb.Release) objkey := testKey(rls.Name, rls.Version) secret, err := newSecretsObject(objkey, rls, nil) - if err != nil { - t.Fatalf("Failed to create secret: %s", err) - } + require.NoError(t, err, "Failed to create secret") mock.objects[objkey] = secret } } @@ -262,9 +256,7 @@ func (mock *MockSecretsInterface) Delete(_ context.Context, name string, _ metav func newTestFixtureSQL(t *testing.T, _ ...*rspb.Release) (*SQL, sqlmock.Sqlmock) { t.Helper() sqlDB, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("error when opening stub database connection: %v", err) - } + require.NoError(t, err, "error when opening stub database connection") sqlxDB := sqlx.NewDb(sqlDB, "sqlmock") return &SQL{ diff --git a/pkg/storage/driver/util_test.go b/pkg/storage/driver/util_test.go index d16043924..7074f252a 100644 --- a/pkg/storage/driver/util_test.go +++ b/pkg/storage/driver/util_test.go @@ -16,12 +16,13 @@ package driver import ( "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestGetSystemLabel(t *testing.T) { - if output := GetSystemLabels(); !reflect.DeepEqual(systemLabels, output) { - t.Errorf("Expected {%v}, got {%v}", systemLabels, output) - } + output := GetSystemLabels() + assert.Truef(t, reflect.DeepEqual(systemLabels, output), "Expected {%v}, got {%v}", systemLabels, output) } func TestIsSystemLabel(t *testing.T) { @@ -32,9 +33,8 @@ func TestIsSystemLabel(t *testing.T) { "NaMe": false, } for label, result := range tests { - if output := isSystemLabel(label); output != result { - t.Errorf("Output %t not equal to expected %t", output, result) - } + output := isSystemLabel(label) + assert.Equalf(t, output, result, "Output %t not equal to expected %t", output, result) } } @@ -68,9 +68,8 @@ func TestFilterSystemLabels(t *testing.T) { }}, } for _, test := range tests { - if output := filterSystemLabels(test[0]); !reflect.DeepEqual(test[1], output) { - t.Errorf("Expected {%v}, got {%v}", test[1], output) - } + output := filterSystemLabels(test[0]) + assert.Truef(t, reflect.DeepEqual(test[1], output), "Expected {%v}, got {%v}", test[1], output) } } @@ -101,8 +100,7 @@ func TestContainsSystemLabels(t *testing.T) { }, false}, } for _, test := range tests { - if output := ContainsSystemLabels(test.input); !reflect.DeepEqual(test.output, output) { - t.Errorf("Expected {%v}, got {%v}", test.output, output) - } + output := ContainsSystemLabels(test.input) + assert.Truef(t, reflect.DeepEqual(test.output, output), "Expected {%v}, got {%v}", test.output, output) } } From 0b1aa55cbb14ce3b7c805a6262e2159c4a70bf73 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:57 +0200 Subject: [PATCH 113/161] chore(pkg): refactor: convert tests to testify assert/require part 22 #### Description refactor: convert tests to testify assert/require in pkg/action Signed-off-by: Matthieu MOREL --- pkg/action/history_test.go | 4 +--- pkg/action/hooks_test.go | 17 ++++++----------- pkg/action/release_testing_test.go | 12 ++++-------- pkg/chart/v2/dependency_test.go | 10 ++++++---- pkg/chart/v2/lint/rules/deprecations_test.go | 11 ++++------- pkg/chart/v2/util/compatible_test.go | 10 ++++++---- pkg/cmd/helpers_test.go | 16 ++++++---------- pkg/cmd/show_test.go | 12 +++++------- pkg/registry/client_http_test.go | 10 ++++------ pkg/registry/registry_test.go | 10 ++++------ 10 files changed, 46 insertions(+), 66 deletions(-) diff --git a/pkg/action/history_test.go b/pkg/action/history_test.go index 31fdd4a96..51212b610 100644 --- a/pkg/action/history_test.go +++ b/pkg/action/history_test.go @@ -50,9 +50,7 @@ func TestHistoryRun(t *testing.T) { client.Max = 3 client.cfg.Releases.MaxHistory = 3 for _, rel := range []*release.Release{simpleRelease, updatedRelease} { - if err := client.cfg.Releases.Create(rel); err != nil { - t.Fatal(err, "Could not add releases to Config") - } + require.NoError(t, client.cfg.Releases.Create(rel), "Could not add releases to Config") } releases, err := config.Releases.ListReleases() diff --git a/pkg/action/hooks_test.go b/pkg/action/hooks_test.go index 20442af13..ad3a4b618 100644 --- a/pkg/action/hooks_test.go +++ b/pkg/action/hooks_test.go @@ -401,16 +401,12 @@ data: serverSideApply := true err := configuration.execHook(&tc.inputRelease, hookEvent, kube.StatusWatcherStrategy, nil, 600, serverSideApply) - if !reflect.DeepEqual(kubeClient.deleteRecord, tc.expectedDeleteRecord) { - t.Fatalf("Got unexpected delete record, expected: %#v, but got: %#v", kubeClient.deleteRecord, tc.expectedDeleteRecord) - } - - if err != nil && !tc.expectError { - t.Fatal("Got an unexpected error.") - } + require.Truef(t, reflect.DeepEqual(kubeClient.deleteRecord, tc.expectedDeleteRecord), "Got unexpected delete record, expected: %#v, but got: %#v", kubeClient.deleteRecord, tc.expectedDeleteRecord) - if err == nil && tc.expectError { - t.Fatal("Expected and error but did not get it.") + if !tc.expectError { + require.NoError(t, err) + } else { + require.Error(t, err) } }) } @@ -490,8 +486,7 @@ data: ctx := context.Background() waitOptions := []kube.WaitOption{kube.WithWaitContext(ctx)} - err := configuration.execHook(rel, release.HookPreInstall, kube.StatusWatcherStrategy, waitOptions, 600, false) - req.NoError(err) + req.NoError(configuration.execHook(rel, release.HookPreInstall, kube.StatusWatcherStrategy, waitOptions, 600, false)) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/release_testing_test.go b/pkg/action/release_testing_test.go index 48a3251a1..91cb548a5 100644 --- a/pkg/action/release_testing_test.go +++ b/pkg/action/release_testing_test.go @@ -190,8 +190,7 @@ func TestGetContainerLogs_MultipleContainers(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "test-pod") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "test-pod")) output := buf.String() assert.Contains(t, output, "POD LOGS: test-pod (main)") assert.Contains(t, output, "POD LOGS: test-pod (sidecar)") @@ -217,8 +216,7 @@ func TestGetContainerLogs_WithInitContainers(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "test-pod") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "test-pod")) output := buf.String() // Init containers should appear before regular containers assert.Contains(t, output, "POD LOGS: test-pod (init-setup)") @@ -230,8 +228,7 @@ func TestGetContainerLogs_PodNotFound(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "nonexistent-pod") - assert.ErrorContains(t, err, "unable to get pod nonexistent-pod") + assert.ErrorContains(t, rt.getContainerLogs(&buf, client, "nonexistent-pod"), "unable to get pod nonexistent-pod") } func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) { @@ -252,8 +249,7 @@ func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "multi-test") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "multi-test")) output := buf.String() assert.Contains(t, output, "POD LOGS: multi-test (container-a)") assert.Contains(t, output, "POD LOGS: multi-test (container-b)") diff --git a/pkg/chart/v2/dependency_test.go b/pkg/chart/v2/dependency_test.go index 35919bd7a..f44a6b06f 100644 --- a/pkg/chart/v2/dependency_test.go +++ b/pkg/chart/v2/dependency_test.go @@ -17,6 +17,8 @@ package v2 import ( "testing" + + "github.com/stretchr/testify/require" ) func TestValidateDependency(t *testing.T) { @@ -35,10 +37,10 @@ func TestValidateDependency(t *testing.T) { } { dep.Alias = value res := dep.Validate() - if res != nil && !shouldFail { - t.Errorf("Failed on case %q", dep.Alias) - } else if res == nil && shouldFail { - t.Errorf("Expected failure for %q", dep.Alias) + if shouldFail { + require.Errorf(t, res, "Expected failure for %q", dep.Alias) + } else { + require.NoErrorf(t, res, "Failed on case %q", dep.Alias) } } } diff --git a/pkg/chart/v2/lint/rules/deprecations_test.go b/pkg/chart/v2/lint/rules/deprecations_test.go index 0aa983678..3c8553cce 100644 --- a/pkg/chart/v2/lint/rules/deprecations_test.go +++ b/pkg/chart/v2/lint/rules/deprecations_test.go @@ -19,6 +19,7 @@ package rules import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -28,17 +29,13 @@ func TestValidateNoDeprecations(t *testing.T) { Kind: "Deployment", } err := validateNoDeprecations(deprecated, nil) - if err == nil { - t.Fatal("Expected deprecated extension to be flagged") - } + require.Error(t, err, "Expected deprecated extension to be flagged") var depErr deprecatedAPIError require.ErrorAs(t, err, &depErr) require.NotEmptyf(t, depErr.Message, "Expected error message to be non-blank") - if err := validateNoDeprecations(&k8sYamlStruct{ + assert.NoError(t, validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", - }, nil); err != nil { - t.Error("Expected a v1 Pod to not be deprecated") - } + }, nil), "Expected a v1 Pod to not be deprecated") } diff --git a/pkg/chart/v2/util/compatible_test.go b/pkg/chart/v2/util/compatible_test.go index e17d33e35..9a57ef64a 100644 --- a/pkg/chart/v2/util/compatible_test.go +++ b/pkg/chart/v2/util/compatible_test.go @@ -17,7 +17,11 @@ limitations under the License. // Package version represents the current version of the project. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestIsCompatibleRange(t *testing.T) { tests := []struct { @@ -36,8 +40,6 @@ func TestIsCompatibleRange(t *testing.T) { } for _, tt := range tests { - if IsCompatibleRange(tt.constraint, tt.ver) != tt.expected { - t.Errorf("expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) - } + assert.Equal(t, tt.expected, IsCompatibleRange(tt.constraint, tt.ver), "expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) } } diff --git a/pkg/cmd/helpers_test.go b/pkg/cmd/helpers_test.go index 3db5f38ab..611d1a54c 100644 --- a/pkg/cmd/helpers_test.go +++ b/pkg/cmd/helpers_test.go @@ -56,17 +56,14 @@ func runTestCmd(t *testing.T, tests []cmdTestCase) { storage := storageFixture() for _, rel := range tt.rels { - if err := storage.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, storage.Create(rel)) } t.Logf("running cmd (attempt %d): %s", i+1, tt.cmd) _, out, err := executeActionCommandC(storage, tt.cmd) - if tt.wantError && err == nil { - t.Errorf("expected error, got success with the following output:\n%s", out) - } - if !tt.wantError && err != nil { - t.Errorf("expected no error, got: '%v'", err) + if tt.wantError { + require.Error(t, err, "expected error, got success with the following output:\n%s", out) + } else { + require.NoError(t, err, "expected no error") } if tt.golden != "" { test.AssertGoldenString(t, out, tt.golden) @@ -294,8 +291,7 @@ func TestCmdGetDryRunFlagStrategy(t *testing.T) { if tc.ExpectedLog != nil { logResult := map[string]string{} - err = json.Unmarshal(logBuf.Bytes(), &logResult) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(logBuf.Bytes(), &logResult)) assert.Equal(t, tc.ExpectedLog.Level, logResult["level"]) assert.Equal(t, tc.ExpectedLog.Msg, logResult["msg"]) diff --git a/pkg/cmd/show_test.go b/pkg/cmd/show_test.go index e24b8c442..3ed01d418 100644 --- a/pkg/cmd/show_test.go +++ b/pkg/cmd/show_test.go @@ -19,9 +19,11 @@ package cmd import ( "fmt" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -32,9 +34,7 @@ func TestShowPreReleaseChart(t *testing.T) { ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) tests := []struct { name string @@ -79,9 +79,7 @@ func TestShowPreReleaseChart(t *testing.T) { _, _, err := executeActionCommand(cmd) if err != nil { if tt.fail { - if !strings.Contains(err.Error(), tt.expectedErr) { - t.Errorf("%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) - } + assert.ErrorContains(t, err, tt.expectedErr, "%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) return } t.Errorf("%q reported error: %s", tt.name, err) diff --git a/pkg/registry/client_http_test.go b/pkg/registry/client_http_test.go index 316a82d3f..0a51b3347 100644 --- a/pkg/registry/client_http_test.go +++ b/pkg/registry/client_http_test.go @@ -39,15 +39,13 @@ func (suite *HTTPRegistryClientTestSuite) TearDownSuite() { } func (suite *HTTPRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptPlainText(true)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptPlainText(true)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptPlainText(true)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptPlainText(true)), "no error logging into registry with good credentials") } func (suite *HTTPRegistryClientTestSuite) Test_1_Push() { diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 429b15113..313cb861c 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -73,10 +73,8 @@ type TestRegistry struct { func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.WorkspaceDir = testWorkspaceDir - err := os.RemoveAll(suite.WorkspaceDir) - suite.Require().NoError(err, "no error removing test workspace dir") - err = os.Mkdir(suite.WorkspaceDir, 0o700) - suite.Require().NoError(err, "no error creating test workspace dir") + suite.Require().NoError(os.RemoveAll(suite.WorkspaceDir), "no error removing test workspace dir") + suite.Require().NoError(os.Mkdir(suite.WorkspaceDir, 0o700), "no error creating test workspace dir") var out bytes.Buffer @@ -92,6 +90,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { ClientOptBasicAuth(testUsername, testPassword), } + var err error if tlsEnabled { var tlsConf *tls.Config if insecure { @@ -122,8 +121,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) suite.Require().NoError(err, "no error generating bcrypt password for test htpasswd file") htpasswdPath := filepath.Join(suite.WorkspaceDir, testHtpasswdFileBasename) - err = os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644) - suite.Require().NoError(err, "no error creating test htpasswd file") + suite.Require().NoError(os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644), "no error creating test htpasswd file") // Registry config config := &configuration.Configuration{} From 33c28395695c53b579c1f94d3dfcadbe2ff2b862 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 20 Jul 2026 20:50:56 +0200 Subject: [PATCH 114/161] chore(pkg): refactor: convert tests to testify assert/require part 19 refactor: convert tests to testify assert/require in pkg/action Signed-off-by: Matthieu MOREL --- pkg/action/lint_test.go | 46 +++++++++------------- pkg/action/show_test.go | 41 ++++++-------------- pkg/action/upgrade_test.go | 40 ++++++++----------- pkg/action/validate_test.go | 37 ++++++------------ pkg/chart/v2/lint/rules/values_test.go | 44 ++++++--------------- pkg/cmd/install_test.go | 6 +-- pkg/cmd/plugin_test.go | 48 +++++++---------------- pkg/getter/getter_test.go | 53 ++++++++++---------------- pkg/storage/driver/records_test.go | 53 ++++++++++---------------- 9 files changed, 125 insertions(+), 243 deletions(-) diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 5b5c2c50a..5c956c682 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/v2/lint/support" ) @@ -89,11 +90,10 @@ func TestLintChart(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := lintChart(tt.chartPath, map[string]any{}, namespace, nil, tt.skipSchemaValidation) - switch { - case err != nil && !tt.err: - t.Errorf("%s", err) - case err == nil && tt.err: - t.Error("Expected a chart parsing error") + if tt.err { + require.Error(t, err, "Expected a chart parsing error") + } else { + require.NoError(t, err) } }) } @@ -106,14 +106,10 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - if len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } + assert.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) actual := result.Errors[0].Error() - if actual != expectedError { - t.Errorf("expected '%s', but got '%s'", expectedError, actual) - } + assert.EqualError(t, result.Errors[0], expectedError, "expected '%s', but got '%s'", expectedError, actual) }) t.Run("should error out for corrupted tgz chart", func(t *testing.T) { @@ -122,31 +118,25 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - if len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } + assert.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) actual := result.Errors[0].Error() - if actual != expectedEOFError { - t.Errorf("expected '%s', but got '%s'", expectedEOFError, actual) - } + assert.EqualError(t, result.Errors[0], expectedEOFError, "expected '%s', but got '%s'", expectedEOFError, actual) }) } func TestLint_MultipleCharts(t *testing.T) { testCharts := []string{chart2MultipleChartLint, chart1MultipleChartLint} testLint := NewLint() - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error(result.Errors) - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors) } func TestLint_EmptyResultErrors(t *testing.T) { testCharts := []string{chart2MultipleChartLint} testLint := NewLint() - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error("Expected no error, got more") - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors, "Expected no error, got more") } func TestLint_ChartWithWarnings(t *testing.T) { @@ -154,18 +144,16 @@ func TestLint_ChartWithWarnings(t *testing.T) { testCharts := []string{chartWithNoTemplatesDir} testLint := NewLint() testLint.Strict = false - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error("Expected no error, got more") - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors, "Expected no error, got more") }) t.Run("should fail with one error when strict", func(t *testing.T) { testCharts := []string{chartWithNoTemplatesDir} testLint := NewLint() testLint.Strict = true - if result := testLint.Run(testCharts, values); len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } + result := testLint.Run(testCharts, values) + assert.Len(t, result.Errors, 1, "expected one error") }) } diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 0dde7fb74..c6c55ead1 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -47,9 +48,7 @@ func TestShow(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `name: alpine @@ -69,9 +68,7 @@ bar baz ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowNoValues(t *testing.T) { @@ -82,13 +79,9 @@ func TestShowNoValues(t *testing.T) { // Regression tests for missing values. See issue #1024. client.OutputFormat = ShowValues output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if output != "" { - t.Errorf("expected empty values buffer, got %s", output) - } + assert.Empty(t, output, "expected empty values buffer, got %s", output) } func TestShowValuesByJsonPathFormat(t *testing.T) { @@ -97,13 +90,9 @@ func TestShowValuesByJsonPathFormat(t *testing.T) { client.JSONPathTemplate = "{$.nestedKey.simpleKey}" client.chart = buildChart(withSampleValues()) output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := "simpleValue" - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowCRDs(t *testing.T) { @@ -121,9 +110,7 @@ func TestShowCRDs(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `--- foo @@ -135,9 +122,7 @@ bar baz ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowNoReadme(t *testing.T) { @@ -154,9 +139,7 @@ func TestShowNoReadme(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `name: alpine @@ -167,9 +150,7 @@ foo bar ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowSetRegistryClient(t *testing.T) { diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 7a73c7179..b7e25206d 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -176,8 +176,8 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { resi, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "arming key removed") - is.Contains(err.Error(), "rollback-on-failure") + req.ErrorContains(err, "arming key removed") + req.ErrorContains(err, "rollback-on-failure") res, err := releaserToV1Release(resi) req.NoError(err) @@ -207,8 +207,8 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { _, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "update fail") - is.Contains(err.Error(), "an error occurred while rolling back the release") + req.ErrorContains(err, "update fail") + is.ErrorContains(err, "an error occurred while rolling back the release") }) } @@ -240,8 +240,7 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { rel.Info.Status = common.StatusDeployed rel.Config = existingValues - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ReuseValues = true // setting newValues and upgrading @@ -303,8 +302,7 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { Config: existingValues, Version: 1, } - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ReuseValues = true sampleChartWithSubChart := buildChart( @@ -373,8 +371,7 @@ func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { rel.Info.Status = common.StatusDeployed rel.Config = existingValues - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ResetThenReuseValues = true // setting newValues and upgrading @@ -417,7 +414,7 @@ func TestUpgradeRelease_Pending(t *testing.T) { vals := map[string]any{} _, err := upAction.Run(rel.Name, buildChart(), vals) - req.Contains(err.Error(), "progress", err) + req.ErrorContains(err, "progress") } func TestUpgradeRelease_Interrupted_Wait(t *testing.T) { @@ -470,7 +467,7 @@ func TestUpgradeRelease_Interrupted_RollbackOnFailure(t *testing.T) { resi, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "release interrupted-release failed, and has been rolled back due to rollback-on-failure being set: context canceled") + req.ErrorContains(err, "release interrupted-release failed, and has been rolled back due to rollback-on-failure being set: context canceled") res, err := releaserToV1Release(resi) req.NoError(err) // Now make sure it is actually upgraded @@ -491,9 +488,8 @@ func TestMergeCustomLabels(t *testing.T) { {map[string]string{"k1": "v1", "k2": "v2"}, map[string]string{"k1": "null", "k2": "v3"}, map[string]string{"k2": "v3"}}, } for _, test := range tests { - if output := mergeCustomLabels(test[0], test[1]); !reflect.DeepEqual(test[2], output) { - t.Errorf("Expected {%v}, got {%v}", test[2], output) - } + output := mergeCustomLabels(test[0], test[1]) + assert.Truef(t, reflect.DeepEqual(test[2], output), "Expected {%v}, got {%v}", test[2], output) } } @@ -511,8 +507,7 @@ func TestUpgradeRelease_Labels(t *testing.T) { } rel.Info.Status = common.StatusDeployed - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.Labels = map[string]string{ "key1": "null", @@ -566,8 +561,7 @@ func TestUpgradeRelease_SystemLabels(t *testing.T) { } rel.Info.Status = common.StatusDeployed - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.Labels = map[string]string{ "key1": "null", @@ -575,12 +569,10 @@ func TestUpgradeRelease_SystemLabels(t *testing.T) { "owner": "val3", } // setting newValues and upgrading - _, err = upAction.Run(rel.Name, buildChart(), nil) - if err == nil { - t.Fatal("expected an error") - } + _, err := upAction.Run(rel.Name, buildChart(), nil) + require.Error(t, err, "expected an error") - is.Equal(fmt.Errorf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) + is.EqualError(err, fmt.Sprintf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels())) } func TestUpgradeRelease_DryRun(t *testing.T) { diff --git a/pkg/action/validate_test.go b/pkg/action/validate_test.go index 878bec599..27097d177 100644 --- a/pkg/action/validate_test.go +++ b/pkg/action/validate_test.go @@ -171,45 +171,38 @@ func TestCheckOwnership(t *testing.T) { deployFoo := newDeploymentResource("foo", "ns-a", "") // Verify that a resource that lacks labels/annotations is not owned - err := checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set managed by label and verify annotation error message _ = accessor.SetLabels(deployFoo.Object, map[string]string{ appManagedByLabel: appManagedByHelm, }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set only the release name annotation and verify missing release namespace error message _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ helmReleaseNameAnnotation: "rel-a", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set both release name and namespace annotations and verify no ownership errors _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ helmReleaseNameAnnotation: "rel-a", helmReleaseNamespaceAnnotation: "ns-a", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.NoError(t, err) + require.NoError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a")) // Verify ownership error for wrong release name - err = checkOwnership(deployFoo.Object, "rel-b", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-b", "ns-a"), `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) // Verify ownership error for wrong release namespace - err = checkOwnership(deployFoo.Object, "rel-a", "ns-b") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-b"), `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) // Verify ownership error for wrong manager label _ = accessor.SetLabels(deployFoo.Object, map[string]string{ appManagedByLabel: "helm", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; label validation error: key "app.kubernetes.io/managed-by" must equal "Helm": current value is "helm"`) + assert.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; label validation error: key "app.kubernetes.io/managed-by" must equal "Helm": current value is "helm"`) } func TestVerifyOwnershipBeforeDelete(t *testing.T) { @@ -306,32 +299,26 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { func TestSetMetadataVisitor(t *testing.T) { var ( - err error deployFoo = newDeploymentResource("foo", "ns-a", "") deployBar = newDeploymentResource("bar", "ns-a-system", "") resources = kube.ResourceList{deployFoo, deployBar} ) // Set release tracking metadata and verify no error - err = resources.Visit(setMetadataVisitor("rel-a", "ns-a", true)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-a", "ns-a", true))) // Verify that release "b" cannot take ownership of "a" - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - require.Error(t, err) + require.Error(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false))) // Force release "b" to take ownership - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", true)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", true))) // Check that there is now no ownership error when setting metadata without force - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false))) // Add a new resource that is missing ownership metadata and verify error resources.Append(newDeploymentResource("baz", "default", "")) - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - assert.ErrorContains(t, err, `Deployment "baz" in namespace "" cannot be owned`) + assert.ErrorContains(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)), `Deployment "baz" in namespace "" cannot be owned`) } func TestValidateNameAndGenerateName(t *testing.T) { diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index 470904049..82e8e660e 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" ) @@ -54,11 +55,7 @@ const testSchema = ` func TestValidateValuesYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm) defer os.Remove(nonExistingValuesFilePath) - - err := validateValuesFileExistence(nonExistingValuesFilePath) - if err == nil { - t.Error("validateValuesFileExistence to return a linter error, got no error") - } + assert.Error(t, validateValuesFileExistence(nonExistingValuesFilePath), "validateValuesFileExistence to return a linter error, got no error") } func TestValidateValuesFileWellFormed(t *testing.T) { @@ -67,9 +64,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err == nil { - t.Fatal("expected values file to fail parsing") - } + require.Error(t, validateValuesFile(valfile, map[string]any{}, false), "expected values file to fail parsing") } func TestValidateValuesFileSchema(t *testing.T) { @@ -78,9 +73,7 @@ func TestValidateValuesFileSchema(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoErrorf(t, validateValuesFile(valfile, map[string]any{}, false), "Failed validation") } func TestValidateValuesFileSchemaFailure(t *testing.T) { @@ -90,9 +83,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, false) - assert.ErrorContains(t, err, "- at '/username': got number, want string") + assert.ErrorContains(t, validateValuesFile(valfile, map[string]any{}, false), "- at '/username': got number, want string") } func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { @@ -102,11 +93,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, true) - if err != nil { - t.Fatal("expected values file to pass parsing because of skipSchemaValidation") - } + require.NoError(t, validateValuesFile(valfile, map[string]any{}, true), "expected values file to pass parsing because of skipSchemaValidation") } func TestValidateValuesFileSchemaOverrides(t *testing.T) { @@ -118,9 +105,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoErrorf(t, validateValuesFile(valfile, overrides, false), "Failed validation") } func TestValidateValuesFile(t *testing.T) { @@ -157,13 +142,10 @@ func TestValidateValuesFile(t *testing.T) { err := validateValuesFile(valfile, tt.overrides, false) - switch { - case err != nil && tt.errorMessage == "": - t.Errorf("Failed validation with %s", err) - case err == nil && tt.errorMessage != "": - t.Error("expected values file to fail parsing") - case err != nil && tt.errorMessage != "": - assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") + if tt.errorMessage == "" { + require.NoErrorf(t, err, "Failed validation with") + } else { + assert.ErrorContains(t, err, tt.errorMessage) } }) } @@ -172,8 +154,6 @@ func TestValidateValuesFile(t *testing.T) { func createTestingSchema(t *testing.T, dir string) string { t.Helper() schemafile := filepath.Join(dir, "values.schema.json") - if err := os.WriteFile(schemafile, []byte(testSchema), 0o700); err != nil { - t.Fatalf("Failed to write schema to tmpdir: %s", err) - } + require.NoErrorf(t, os.WriteFile(schemafile, []byte(testSchema), 0o700), "Failed to write schema to tmpdir") return schemafile } diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index 8d3435e03..d1e081e5c 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -23,6 +23,8 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -39,9 +41,7 @@ func TestInstall(t *testing.T) { })) defer srv2.Close() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) repoFile := filepath.Join(srv.Root(), "repositories.yaml") diff --git a/pkg/cmd/plugin_test.go b/pkg/cmd/plugin_test.go index 5364423a0..6a7980119 100644 --- a/pkg/cmd/plugin_test.go +++ b/pkg/cmd/plugin_test.go @@ -72,14 +72,10 @@ func TestManuallyProcessArgs(t *testing.T) { known, unknown := manuallyProcessArgs(input) for i, k := range known { - if k != expectKnown[i] { - t.Errorf("expected known flag %d to be %q, got %q", i, expectKnown[i], k) - } + assert.Equal(t, expectKnown[i], k, "expected known flag %d to be %q, got %q", i, expectKnown[i], k) } for i, k := range unknown { - if k != expectUnknown[i] { - t.Errorf("expected unknown flag %d to be %q, got %q", i, expectUnknown[i], k) - } + assert.Equal(t, expectUnknown[i], k, "expected unknown flag %d to be %q, got %q", i, expectUnknown[i], k) } } @@ -130,23 +126,17 @@ func TestLoadCLIPlugins(t *testing.T) { pluginCmd := pluginCmds[i] t.Run(fmt.Sprintf("%s-%d", pluginCmd.Name(), i), func(t *testing.T) { out.Reset() - if pluginCmd.Use != tt.use { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.use, pluginCmd.Use) - } - if pluginCmd.Short != tt.short { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.short, pluginCmd.Short) - } - if pluginCmd.Long != tt.long { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.long, pluginCmd.Long) - } + assert.Equal(t, tt.use, pluginCmd.Use, "%d: Expected Use=%q, got %q", i, tt.use, pluginCmd.Use) + assert.Equal(t, tt.short, pluginCmd.Short, "%d: Expected Use=%q, got %q", i, tt.short, pluginCmd.Short) + assert.Equal(t, tt.long, pluginCmd.Long, "%d: Expected Use=%q, got %q", i, tt.long, pluginCmd.Long) // Currently, plugins assume a Linux subsystem. Skip the execution // tests until this is fixed if runtime.GOOS != "windows" { if err := pluginCmd.RunE(pluginCmd, tt.args); err != nil { - if assert.Positive(t, tt.code, "Error running %s: %+v", tt.use, err) { + if assert.Positive(t, tt.code, "Error running %s", tt.use) { var cerr CommandError - require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err) + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError", tt.use) assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } @@ -190,31 +180,23 @@ func TestLoadPluginsWithSpace(t *testing.T) { plugins := cmd.Commands() - if len(plugins) != len(tests) { - t.Fatalf("Expected %d plugins, got %d", len(tests), len(plugins)) - } + require.Len(t, plugins, len(tests), "Expected %d plugins, got %d", len(tests), len(plugins)) for i := range plugins { out.Reset() tt := tests[i] pp := plugins[i] - if pp.Use != tt.use { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.use, pp.Use) - } - if pp.Short != tt.short { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.short, pp.Short) - } - if pp.Long != tt.long { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.long, pp.Long) - } + assert.Equal(t, tt.use, pp.Use, "%d: Expected Use=%q, got %q", i, tt.use, pp.Use) + assert.Equal(t, tt.short, pp.Short, "%d: Expected Use=%q, got %q", i, tt.short, pp.Short) + assert.Equal(t, tt.long, pp.Long, "%d: Expected Use=%q, got %q", i, tt.long, pp.Long) // Currently, plugins assume a Linux subsystem. Skip the execution // tests until this is fixed if runtime.GOOS != "windows" { if err := pp.RunE(pp, tt.args); err != nil { - if assert.Positive(t, tt.code, "Error running %s: %+v", tt.use, err) { + if assert.Positive(t, tt.code, "Error running %s", tt.use) { var cerr CommandError - require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError: got %v(%T)", tt.use, err, err) + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError", tt.use) assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } @@ -334,9 +316,7 @@ func TestLoadCLIPlugins_HelmNoPlugins(t *testing.T) { loadCLIPlugins(cmd, out) plugins := cmd.Commands() - if len(plugins) != 0 { - t.Fatalf("Expected 0 plugins, got %d", len(plugins)) - } + require.Empty(t, plugins, "Expected 0 plugins, got %d", len(plugins)) } func TestPluginCmdsCompletion(t *testing.T) { diff --git a/pkg/getter/getter_test.go b/pkg/getter/getter_test.go index 3a09b4d82..67cfc2ef0 100644 --- a/pkg/getter/getter_test.go +++ b/pkg/getter/getter_test.go @@ -19,6 +19,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" ) @@ -30,9 +33,7 @@ func TestProvider(t *testing.T) { func(_ ...Option) (Getter, error) { return nil, nil }, } - if !p.Provides("three") { - t.Error("Expected provider to provide three") - } + assert.True(t, p.Provides("three"), "Expected provider to provide three") } func TestProviders(t *testing.T) { @@ -41,34 +42,25 @@ func TestProviders(t *testing.T) { {[]string{"two", "four"}, func(_ ...Option) (Getter, error) { return nil, nil }}, } - if _, err := ps.ByScheme("one"); err != nil { - t.Error(err) - } - if _, err := ps.ByScheme("four"); err != nil { - t.Error(err) - } + _, err := ps.ByScheme("one") + require.NoError(t, err) + _, err = ps.ByScheme("four") + require.NoError(t, err) - if _, err := ps.ByScheme("five"); err == nil { - t.Error("Did not expect handler for five") - } + _, err = ps.ByScheme("five") + assert.Error(t, err, "Did not expect handler for five") } func TestProvidersWithTimeout(t *testing.T) { want := time.Hour getters := Getters(WithTimeout(want)) getter, err := getters.ByScheme("http") - if err != nil { - t.Error(err) - } + require.NoError(t, err) httpGetter := getter.(*HTTPGetter) client, err := httpGetter.httpClient(httpGetter.opts) - if err != nil { - t.Error(err) - } + require.NoError(t, err) got := client.Timeout - if got != want { - t.Errorf("Expected %q, got %q", want, got) - } + assert.Equal(t, want, got, "Expected %q, got %q", want, got) } func TestAll(t *testing.T) { @@ -76,13 +68,10 @@ func TestAll(t *testing.T) { env.PluginsDirectory = pluginDir all := All(env) - if len(all) != 4 { - t.Errorf("expected 4 providers (default plus three plugins), got %d", len(all)) - } + assert.Len(t, all, 4, "expected 4 providers (default plus three plugins), got %d", len(all)) - if _, err := all.ByScheme("test2"); err != nil { - t.Error(err) - } + _, err := all.ByScheme("test2") + assert.NoError(t, err) } func TestByScheme(t *testing.T) { @@ -90,10 +79,8 @@ func TestByScheme(t *testing.T) { env.PluginsDirectory = pluginDir g := All(env) - if _, err := g.ByScheme("test"); err != nil { - t.Error(err) - } - if _, err := g.ByScheme("https"); err != nil { - t.Error(err) - } + _, err := g.ByScheme("test") + require.NoError(t, err) + _, err = g.ByScheme("https") + assert.NoError(t, err) } diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index cd1064342..067e31e76 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -20,6 +20,9 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/release/common" ) @@ -50,10 +53,11 @@ func TestRecordsAdd(t *testing.T) { } for _, tt := range tests { - if err := rs.Add(tt.rec); err != nil { - if !tt.ok { - t.Fatalf("failed: %q: %s\n", tt.desc, err) - } + err := rs.Add(tt.rec) + if !tt.ok { + require.NoError(t, err, "failed: %q:", tt.desc) + } else { + require.Error(t, err) } } } @@ -77,23 +81,18 @@ func TestRecordsRemove(t *testing.T) { startLen := rs.Len() for _, tt := range tests { - if r := rs.Remove(tt.key); r == nil { - if !tt.ok { - t.Fatalf("Failed to %q (key = %s). Expected nil, got %v", - tt.desc, - tt.key, - r, - ) - } + r := rs.Remove(tt.key) + if tt.ok { + require.Nil(t, r, "Failed to %q (key = %s). Expected nil, got %v", tt.desc, tt.key, r) + } else { + require.NotNil(t, r) } } // We expect the total number of records will be less now than there were // when we started. endLen := rs.Len() - if endLen >= startLen { - t.Errorf("expected ending length %d to be less than starting length %d", endLen, startLen) - } + assert.Lessf(t, endLen, startLen, "expected ending length %d to be less than starting length %d", endLen, startLen) } func TestRecordsRemoveAt(t *testing.T) { @@ -102,14 +101,10 @@ func TestRecordsRemoveAt(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - if len(rs) != 2 { - t.Fatal("Expected len=2 for mock") - } + require.Len(t, rs, 2, "Expected len=2 for mock") rs.Remove("rls-a.v1") - if len(rs) != 1 { - t.Fatalf("Expected length of rs to be 1, got %d", len(rs)) - } + require.Len(t, rs, 1, "Expected length of rs to be 1, got %d", len(rs)) } func TestRecordsGet(t *testing.T) { @@ -137,9 +132,7 @@ func TestRecordsGet(t *testing.T) { for _, tt := range tests { got := rs.Get(tt.key) - if !reflect.DeepEqual(tt.rec, got) { - t.Fatalf("Expected %v, got %v", tt.rec, got) - } + require.Truef(t, reflect.DeepEqual(tt.rec, got), "Expected %v, got %v", tt.rec, got) } } @@ -168,9 +161,7 @@ func TestRecordsIndex(t *testing.T) { for _, tt := range tests { got, _ := rs.Index(tt.key) - if got != tt.sort { - t.Fatalf("Expected %d, got %d", tt.sort, got) - } + require.Equal(t, tt.sort, got, "Expected %d, got %d", tt.sort, got) } } @@ -199,9 +190,7 @@ func TestRecordsExists(t *testing.T) { for _, tt := range tests { got := rs.Exists(tt.key) - if got != tt.ok { - t.Fatalf("Expected %t, got %t", tt.ok, got) - } + require.Equal(t, tt.ok, got, "Expected %t, got %t", tt.ok, got) } } @@ -233,8 +222,6 @@ func TestRecordsReplace(t *testing.T) { for _, tt := range tests { got := rs.Replace(tt.key, tt.rec) - if !reflect.DeepEqual(tt.expected, got) { - t.Fatalf("Expected %v, got %v", tt.expected, got) - } + require.Truef(t, reflect.DeepEqual(tt.expected, got), "Expected %v, got %v", tt.expected, got) } } From cd4c5d3bfd7d19be9a3a01ba63a650cf044e1409 Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Tue, 21 Jul 2026 14:38:44 -0600 Subject: [PATCH 115/161] chore: group github-actions dependabot updates Signed-off-by: Terry Howe --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d8e8e3379..1b1de9e55 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -37,9 +37,17 @@ updates: directory: "/" schedule: interval: "daily" + groups: + github-actions: + patterns: + - "*" - # Keep dev-v3 GitHub Actions up to date, while Helm v3 is within support package-ecosystem: "github-actions" target-branch: "dev-v3" directory: "/" schedule: interval: "daily" + groups: + github-actions: + patterns: + - "*" From 065d3a6a3dcda016a9de88a9b32f0e9eedcf0876 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:33:05 +0000 Subject: [PATCH 116/161] chore(deps): bump github/codeql-action/analyze from 4.37.1 to 4.37.2 Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.37.1 to 4.37.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1) --- updated-dependencies: - dependency-name: github/codeql-action/analyze dependency-version: 4.37.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d02d55b82..53a76f6f6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 + uses: github/codeql-action/analyze@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 From cdccef4818c06e4d1ee9521cfb9bcadc30c282e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:33:15 +0000 Subject: [PATCH 117/161] chore(deps): bump github/codeql-action/init from 4.37.1 to 4.37.2 Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.37.1 to 4.37.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d02d55b82..1e7748d44 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 + uses: github/codeql-action/init@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. From a0f954e277702f87883d18760207b34ba3efbf80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:33:23 +0000 Subject: [PATCH 118/161] chore(deps): bump github/codeql-action/autobuild from 4.37.1 to 4.37.2 Bumps [github/codeql-action/autobuild](https://github.com/github/codeql-action) from 4.37.1 to 4.37.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1) --- updated-dependencies: - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d02d55b82..d28011b0a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1 + uses: github/codeql-action/autobuild@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl From 5223ceacda672bdd72efe8995d4abd9327c6539c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:08:04 -0600 Subject: [PATCH 119/161] chore(deps): bump github/codeql-action/upload-sarif (#32440) Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.37.1 to 4.37.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e0647621c2984b5ed2f768cb892365bf2a616ad1) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 41f97dd45..879ff1325 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 + uses: github/codeql-action/upload-sarif@e0647621c2984b5ed2f768cb892365bf2a616ad1 # v4.37.2 with: sarif_file: results.sarif From ed246e29f7940fffa4631aa67cfef66c5722d4a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:08:39 -0600 Subject: [PATCH 120/161] chore(deps): bump actions/labeler from 6.2.0 to 7.0.0 (#32441) Bumps [actions/labeler](https://github.com/actions/labeler) from 6.2.0 to 7.0.0. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/b8dd2d9be0f68b860e7dae5dae7d772984eacd6d...bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13) --- updated-dependencies: - dependency-name: actions/labeler dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/label-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml index 5c2b2fa17..11f0f5d00 100644 --- a/.github/workflows/label-pr.yml +++ b/.github/workflows/label-pr.yml @@ -11,6 +11,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # pin@v6.2.0 + - uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # pin@v7.0.0 with: sync-labels: true From fe3f98b5641fe3a0a9fa2575df8698136c2a0029 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 09:11:20 +0000 Subject: [PATCH 121/161] chore(deps): bump google.golang.org/grpc from 1.80.0 to 1.82.1 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.80.0 to 1.82.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.80.0...v1.82.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-version: 1.82.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 016b0fded..dffe65d46 100644 --- a/go.mod +++ b/go.mod @@ -165,9 +165,9 @@ require ( golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.47.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect - google.golang.org/grpc v1.80.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index d097bc72c..ded47f4be 100644 --- a/go.sum +++ b/go.sum @@ -465,12 +465,12 @@ golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= From ea7c838e0875449a4b2fe141a961aa29f1435a5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 19:09:19 +0000 Subject: [PATCH 122/161] chore(deps): bump the github-actions group with 4 updates Bumps the github-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.2 to 4.37.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) Updates `github/codeql-action/autobuild` from 4.37.2 to 4.37.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) Updates `github/codeql-action/analyze` from 4.37.2 to 4.37.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) Updates `github/codeql-action/upload-sarif` from 4.37.2 to 4.37.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e0647621c2984b5ed2f768cb892365bf2a616ad1...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecards.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b85756718..d8c1a9d12 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 + uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 + uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e0647621c2984b5ed2f768cb892365bf2a616ad1 # pinv4.37.2 + uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 879ff1325..d8f878f10 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e0647621c2984b5ed2f768cb892365bf2a616ad1 # v4.37.2 + uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 with: sarif_file: results.sarif From 050d3e99b9dc8796ced4b99cb272cba91c43055f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 04:32:02 -0600 Subject: [PATCH 123/161] chore(deps): bump ossf/scorecard-action in the github-actions group (#32458) Bumps the github-actions group with 1 update: [ossf/scorecard-action](https://github.com/ossf/scorecard-action). Updates `ossf/scorecard-action` from 2.4.3 to 2.4.4 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/4eaacf0543bb3f2c246792bd56e8cdeffafb205a...2d1146689b8cda280b9bc96326124645441f03bc) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-version: 2.4.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d8f878f10..6c142b511 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -33,7 +33,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif From 8f74dce6ba8d7264ce75f52507616720865e712d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 04:40:32 -0600 Subject: [PATCH 124/161] chore(deps): bump the k8s-io group across 1 directory with 7 updates (#32459) Bumps the k8s-io group with 4 updates in the / directory: [k8s.io/api](https://github.com/kubernetes/api), [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver), [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) and [k8s.io/kubectl](https://github.com/kubernetes/kubectl). Updates `k8s.io/api` from 0.36.2 to 0.36.3 - [Commits](https://github.com/kubernetes/api/compare/v0.36.2...v0.36.3) Updates `k8s.io/apiextensions-apiserver` from 0.36.2 to 0.36.3 - [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases) - [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.36.2...v0.36.3) Updates `k8s.io/apimachinery` from 0.36.2 to 0.36.3 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.36.2...v0.36.3) Updates `k8s.io/apiserver` from 0.36.2 to 0.36.3 - [Commits](https://github.com/kubernetes/apiserver/compare/v0.36.2...v0.36.3) Updates `k8s.io/cli-runtime` from 0.36.2 to 0.36.3 - [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.36.2...v0.36.3) Updates `k8s.io/client-go` from 0.36.2 to 0.36.3 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.36.2...v0.36.3) Updates `k8s.io/kubectl` from 0.36.2 to 0.36.3 - [Commits](https://github.com/kubernetes/kubectl/compare/v0.36.2...v0.36.3) --- updated-dependencies: - dependency-name: k8s.io/api dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apiextensions-apiserver dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apiserver dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/cli-runtime dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/kubectl dependency-version: 0.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 18 +++++++++--------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index dffe65d46..6b9878bb2 100644 --- a/go.mod +++ b/go.mod @@ -39,14 +39,14 @@ require ( golang.org/x/term v0.45.0 golang.org/x/text v0.40.0 gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.36.2 - k8s.io/apiextensions-apiserver v0.36.2 - k8s.io/apimachinery v0.36.2 - k8s.io/apiserver v0.36.2 - k8s.io/cli-runtime v0.36.2 - k8s.io/client-go v0.36.2 + k8s.io/api v0.36.3 + k8s.io/apiextensions-apiserver v0.36.3 + k8s.io/apimachinery v0.36.3 + k8s.io/apiserver v0.36.3 + k8s.io/cli-runtime v0.36.3 + k8s.io/client-go v0.36.3 k8s.io/klog/v2 v2.140.0 - k8s.io/kubectl v0.36.2 + k8s.io/kubectl v0.36.3 oras.land/oras-go/v2 v2.6.2 sigs.k8s.io/controller-runtime v0.24.1 sigs.k8s.io/kustomize/kyaml v0.21.1 @@ -172,11 +172,11 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/component-base v0.36.2 // indirect + k8s.io/component-base v0.36.3 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/kustomize/api v0.21.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) diff --git a/go.sum b/go.sum index ded47f4be..e5933d99a 100644 --- a/go.sum +++ b/go.sum @@ -487,26 +487,26 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= -k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= -k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4= -k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA= -k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= -k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= -k8s.io/apiserver v0.36.2 h1:6vMnkmHZPeBloNkHUhmZYq7Ylv8WIB8xjyEl+eSt26E= -k8s.io/apiserver v0.36.2/go.mod h1:9PoQ2ikCytrZyZg11mGhLEF5m8Rgsb5FJmYJ4Wvnl1k= -k8s.io/cli-runtime v0.36.2 h1:CconTvEeV4DJs4ZX3HQKCFbFRGsm6OtuBM9yjmMP2VM= -k8s.io/cli-runtime v0.36.2/go.mod h1:LddcjiMf4YlnHO7c1Y7rEtDqL84FyiYVLco7V679GUU= -k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI= -k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0= -k8s.io/component-base v0.36.2 h1:Z0VH80O7Ng0HDZnZj3WRR3urEGa0kTwmO8CwEwjVK1w= -k8s.io/component-base v0.36.2/go.mod h1:mGfFOA7Gwpdm1VW2cwSQYbiDIlz8GD2WGwH88QSeCyA= +k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w= +k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg= +k8s.io/apiextensions-apiserver v0.36.3 h1:dPmOAPhwTtqb1bTxbFPsy18KHPhktQeO3WUPXunZIB0= +k8s.io/apiextensions-apiserver v0.36.3/go.mod h1:KTXFqgXiuw2pRoL+Wpmttqc+up9Xt/GohadPWeLLOa4= +k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= +k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= +k8s.io/apiserver v0.36.3 h1:MGSg2SkdfuytiDEcRylT5mQFmmSsbx90XFUO67Y4bsQ= +k8s.io/apiserver v0.36.3/go.mod h1:fVH7zv9EUNUA7Fl7LtDKh8aB9W7u1VQPSGtWV5SjUxg= +k8s.io/cli-runtime v0.36.3 h1:g+eJ+M1sYpnNYp/q5fzaw2KejIL0Q7DH+xFl6YVoL4U= +k8s.io/cli-runtime v0.36.3/go.mod h1:hZpAqK8nSFXvvLaVCbzUPVp8e9TRLSTCfpNzMt7s3tE= +k8s.io/client-go v0.36.3 h1:M4JdVzXxYcZk4fGpfDdYnxSwhLKWCFoQsHW6t+z8Hfg= +k8s.io/client-go v0.36.3/go.mod h1:gcPwr0c87vjjG6HB6pWEqOeuYVoXSsREjzux2j6GF30= +k8s.io/component-base v0.36.3 h1:vc/UFvPCkW0irPz84LAodAL1j3f4xktPM6dDJIEheAY= +k8s.io/component-base v0.36.3/go.mod h1:hZbNFG+gCMl9EbykDGEu73feKP9/Cq6JsV4pTo9GTO8= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/kubectl v0.36.2 h1:rpUGGpeL09XVOLep2yle5jrtk//JA1L6ZHfkQQtVEwk= -k8s.io/kubectl v0.36.2/go.mod h1:gVbQ3B/yb4bSR2ggQ7rd0W6icUSWs7sduH4e16Vii+0= +k8s.io/kubectl v0.36.3 h1:TesKp+XYQEjPYoFvuobcVnuvira2+/xAVlq//+kksaI= +k8s.io/kubectl v0.36.3/go.mod h1:W+NEb1CzBGmoaI1Nrpn2ETo9omNBl0AsyxnnMT40N6E= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo= @@ -521,7 +521,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= From 5142ca8ddca79a19c8529508c77ab4b27cb23a8f Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 13:24:06 +0200 Subject: [PATCH 125/161] chore(internal): refactor: finer tests conversions to testify part 1 #### Description refactor: finer tests conversions to testify in internal/chart/v3/util Signed-off-by: Matthieu MOREL --- internal/chart/v3/lint/lint_test.go | 15 +++--- internal/chart/v3/lint/rules/crds_test.go | 3 +- internal/chart/v3/lint/rules/template_test.go | 11 ++-- .../chart/v3/lint/support/message_test.go | 6 +-- internal/chart/v3/loader/load_test.go | 31 ++++------- internal/chart/v3/util/chartfile_test.go | 19 +------ internal/chart/v3/util/expand_test.go | 4 +- internal/chart/v3/util/save_test.go | 5 +- .../plugin/installer/http_installer_test.go | 26 +++++----- internal/plugin/installer/installer_test.go | 2 - .../plugin/installer/vcs_installer_test.go | 25 ++++----- internal/plugin/subprocess_commands_test.go | 15 +++--- .../release/v2/util/manifest_sorter_test.go | 1 - internal/resolver/resolver_test.go | 52 ++++++++----------- 14 files changed, 84 insertions(+), 131 deletions(-) diff --git a/internal/chart/v3/lint/lint_test.go b/internal/chart/v3/lint/lint_test.go index 8916c6e22..b0a7ce651 100644 --- a/internal/chart/v3/lint/lint_test.go +++ b/internal/chart/v3/lint/lint_test.go @@ -114,7 +114,7 @@ func TestBadValuesV3(t *testing.T) { func TestBadCrdFileV3(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages - assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) + require.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } @@ -122,8 +122,7 @@ func TestBadCrdFileV3(t *testing.T) { func TestGoodChart(t *testing.T) { var values map[string]any m := RunAll(goodChartDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } @@ -143,13 +142,12 @@ func TestHelmCreateChart(t *testing.T) { // Note: we test with strict=true here, even though others have // strict = false. m := RunAll(createdChart, values, namespace, WithSkipSchemaValidation(true)).Messages - if ll := len(m); ll != 1 { - t.Errorf("All should have had exactly 1 error. Got %d", ll) + if !assert.Len(t, m, 1, "All should have had exactly 1 error") { for i, msg := range m { t.Logf("Message %d: %s", i, msg.Error()) } - } else if msg := m[0].Err.Error(); !strings.Contains(msg, "icon is recommended") { - t.Errorf("Unexpected lint error: %s", msg) + } else { + assert.ErrorContains(t, m[0].Err, "icon is recommended") } } @@ -192,8 +190,7 @@ func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { func TestSubChartValuesChart(t *testing.T) { var values map[string]any m := RunAll(subChartValuesDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } diff --git a/internal/chart/v3/lint/rules/crds_test.go b/internal/chart/v3/lint/rules/crds_test.go index 60cb1b5ba..9009c1801 100644 --- a/internal/chart/v3/lint/rules/crds_test.go +++ b/internal/chart/v3/lint/rules/crds_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/chart/v3/lint/support" ) @@ -33,7 +34,7 @@ func TestInvalidCrdsDir(t *testing.T) { Crds(&linter) res := linter.Messages - assert.Len(t, res, 1) + require.Len(t, res, 1) assert.ErrorContains(t, res[0].Err, "not a directory") } diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index b4fa2d311..3271a5bbe 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -199,12 +199,12 @@ func TestDeprecatedAPIFails(t *testing.T) { linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) - if l := len(linter.Messages); l != 1 { + if !assert.Len(t, linter.Messages, 1) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 1 lint error, got %d", l) } + require.Len(t, linter.Messages, 1, "Expected 1 lint error") var err deprecatedAPIError require.ErrorAs(t, linter.Messages[0].Err, &err, "Expected error to be of type deprecatedAPIError") @@ -252,8 +252,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { ChartDir: filepath.Join(dir, ch.Metadata.Name), } Templates(linter, ch.Values, namespace, strict) - if len(linter.Messages) != 0 { - t.Errorf("expected zero messages, got %d", len(linter.Messages)) + if !assert.Empty(t, linter.Messages, "expected zero messages") { for i, msg := range linter.Messages { t.Logf("Message %d: %q", i, msg) } @@ -376,12 +375,12 @@ func TestEmptyWithCommentsManifests(t *testing.T) { linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) - if l := len(linter.Messages); l > 0 { + if !assert.Empty(t, linter.Messages) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 0 lint errors, got %d", l) } + require.Empty(t, linter.Messages, "Expected 0 lint errors") } func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ diff --git a/internal/chart/v3/lint/support/message_test.go b/internal/chart/v3/lint/support/message_test.go index 4c3ed3a3f..d07cf9ed4 100644 --- a/internal/chart/v3/lint/support/message_test.go +++ b/internal/chart/v3/lint/support/message_test.go @@ -58,11 +58,11 @@ func TestRunLinterRule(t *testing.T) { func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - require.EqualErrorf(t, m, "[ERROR] Chart.yaml: Foo", "Unexpected output: %s", m.Error()) + require.EqualError(t, m, "[ERROR] Chart.yaml: Foo") m = Message{WarningSev, "templates/", errors.New("Bar")} - require.EqualErrorf(t, m, "[WARNING] templates/: Bar", "Unexpected output: %s", m.Error()) + require.EqualError(t, m, "[WARNING] templates/: Bar") m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - assert.EqualErrorf(t, m, "[INFO] templates/rc.yaml: FooBar", "Unexpected output: %s", m.Error()) + assert.EqualError(t, m, "[INFO] templates/rc.yaml: FooBar") } diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index 9378bcdf5..dd5fdc8db 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -25,7 +25,6 @@ import ( "log" "os" "path/filepath" - "reflect" "runtime" "strings" "testing" @@ -201,11 +200,9 @@ icon: https://example.com/64x64.png require.NoError(t, err, "Expected good files to be loaded") assert.Equal(t, "frobnitz", c.Name(), "Expected chart name to be 'frobnitz', got %s", c.Name()) assert.Equal(t, "some values", c.Values["var"], "Expected chart values to be populated with default values") - assert.Len(t, c.Raw, 5, "Expected %d files, got %d", 5, len(c.Raw)) - + assert.Len(t, c.Raw, 5, "Expected 5 files") assert.True(t, bytes.Equal(c.Schema, []byte("type: Values")), "Expected chart schema to be populated with default values") - - assert.Len(t, c.Templates, 2, "Expected number of templates == 2, got %d", len(c.Templates)) + assert.Len(t, c.Templates, 2, "Expected 2 templates") _, err = LoadFiles([]*archive.BufferedFile{}) require.Error(t, err, "Expected err to be non-nil") @@ -417,7 +414,7 @@ foo: t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) require.NoError(tt, err) - assert.Truef(tt, reflect.DeepEqual(values, testCase.expctedValues), "Expected values: %v, got %v", testCase.expctedValues, values) + assert.Equalf(tt, testCase.expctedValues, values, "Expected values: %v, got %v", testCase.expctedValues, values) }) } } @@ -445,16 +442,13 @@ func TestMergeValuesV3(t *testing.T) { } testMap := MergeMaps(flatMap, nestedMap) - equal := reflect.DeepEqual(testMap, nestedMap) - assert.True(t, equal, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) + assert.Equal(t, testMap, nestedMap, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) - equal = reflect.DeepEqual(testMap, flatMap) - assert.True(t, equal, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) + assert.Equal(t, testMap, flatMap, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) - equal = reflect.DeepEqual(testMap, anotherNestedMap) - assert.True(t, equal, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) + assert.Equal(t, testMap, anotherNestedMap, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -465,26 +459,23 @@ func TestMergeValuesV3(t *testing.T) { "awesome": "stuff", }, } - equal = reflect.DeepEqual(testMap, expectedMap) - assert.True(t, equal, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) + assert.Equal(t, expectedMap, testMap, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { t.Helper() require.NotEmpty(t, c.Name(), "No chart metadata found on %v", c) t.Logf("Verifying chart %s", c.Name()) - assert.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) + assert.Len(t, c.Templates, 1, "Expected 1 template") numfiles := 6 - if len(c.Files) != numfiles { - t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files)) + if !assert.Len(t, c.Files, numfiles, "Expected %d extra files", numfiles) { for _, n := range c.Files { t.Logf("\t%s", n.Name) } } - if len(c.Dependencies()) != 2 { - t.Errorf("Expected 2 dependencies, got %d (%v)", len(c.Dependencies()), c.Dependencies()) + if !assert.Len(t, c.Dependencies(), 2, "Expected 2 dependencies") { for _, d := range c.Dependencies() { t.Logf("\tSubchart: %s\n", d.Name()) } @@ -509,7 +500,7 @@ func verifyChart(t *testing.T, c *chart.Chart) { func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies") tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, diff --git a/internal/chart/v3/util/chartfile_test.go b/internal/chart/v3/util/chartfile_test.go index 0cc8a66af..850f39af2 100644 --- a/internal/chart/v3/util/chartfile_test.go +++ b/internal/chart/v3/util/chartfile_test.go @@ -36,36 +36,21 @@ func TestLoadChartfile(t *testing.T) { func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { t.Helper() require.NotNil(t, f, "Failed verifyChartfile because f is nil") - assert.Equal(t, name, f.Name, "Expected %s, got %s", name, f.Name) - assert.Equal(t, "This is a frobnitz.", f.Description, "Unexpected description %q", f.Description) - assert.Equal(t, "1.2.3", f.Version, "Unexpected version %q", f.Version) - assert.Len(t, f.Maintainers, 2, "Expected 2 maintainers, got %d", len(f.Maintainers)) - assert.Equal(t, "The Helm Team", f.Maintainers[0].Name, "Unexpected maintainer name.") - assert.Equal(t, "nobody@example.com", f.Maintainers[1].Email, "Unexpected maintainer email.") - require.Len(t, f.Sources, 1, "Unexpected number of sources") - assert.Equal(t, "https://example.com/foo/bar", f.Sources[0], "Expected https://example.com/foo/bar, got %s", f.Sources) - assert.Equal(t, "http://example.com", f.Home, "Unexpected home.") - assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) - require.Len(t, f.Keywords, 3, "Unexpected keywords") - require.Len(t, f.Annotations, 2, "Unexpected annotations") - want, got := "extravalue", f.Annotations["extrakey"] - assert.Equalf(t, want, got, "Want %q, but got %q", want, got) - - want, got = "anothervalue", f.Annotations["anotherkey"] - assert.Equalf(t, want, got, "Want %q, but got %q", want, got) + assert.Equal(t, "extravalue", f.Annotations["extrakey"]) + assert.Equal(t, "anothervalue", f.Annotations["anotherkey"]) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { diff --git a/internal/chart/v3/util/expand_test.go b/internal/chart/v3/util/expand_test.go index e6d66b74e..ddf74b392 100644 --- a/internal/chart/v3/util/expand_test.go +++ b/internal/chart/v3/util/expand_test.go @@ -101,7 +101,7 @@ func TestExpand(t *testing.T) { require.NoError(t, err) expectLen := 11 - assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) + assert.Len(t, fis, expectLen, "Expected %d files", expectLen) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) @@ -154,7 +154,7 @@ func TestExpandFile(t *testing.T) { require.NoError(t, err) expectLen := 11 - assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) + assert.Len(t, fis, expectLen, "Expected %d files", expectLen) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index f7bd5dcfb..26bb54019 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -69,9 +69,8 @@ func TestSave(t *testing.T) { c2, err := loader.LoadFile(where) require.NoError(t, err) require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { - t.Fatal("Files data did not match") - } + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, "scheherazade/shahryar.txt", c2.Files[0].Name, "Files data did not match") if !bytes.Equal(c.Schema, c2.Schema) { indentation := 4 diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index d0d5e099d..df8385ed6 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -67,10 +67,10 @@ func mockArchiveServer() *httptest.Server { if !strings.HasSuffix(r.URL.Path, ".tar.gz") { w.Header().Add("Content-Type", "text/html") fmt.Fprintln(w, "broken") - return + } else { + w.Header().Add("Content-Type", "application/gzip") + fmt.Fprintln(w, "test") } - w.Header().Add("Content-Type", "application/gzip") - fmt.Fprintln(w, "test") })) } @@ -221,22 +221,22 @@ func TestExtract(t *testing.T) { expectedReadmePerm := os.FileMode(0o777 &^ currentUmask) pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") - if info, err := os.Stat(pluginYAMLFullPath); err != nil { + info, err := os.Stat(pluginYAMLFullPath) + if err != nil { require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", pluginYAMLFullPath) - t.Fatal(err) - } else { - require.Equalf(t, expectedPluginYAMLPerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", - pluginYAMLFullPath, expectedPluginYAMLPerm, info.Mode().Perm(), currentUmask) } + require.NoError(t, err) + require.Equalf(t, expectedPluginYAMLPerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", + pluginYAMLFullPath, expectedPluginYAMLPerm, info.Mode().Perm(), currentUmask) readmeFullPath := filepath.Join(tempDir, "README.md") - if info, err := os.Stat(readmeFullPath); err != nil { + info, err = os.Stat(readmeFullPath) + if err != nil { require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", readmeFullPath) - t.Fatal(err) - } else { - require.Equalf(t, expectedReadmePerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", - readmeFullPath, expectedReadmePerm, info.Mode().Perm(), currentUmask) } + require.NoError(t, err) + require.Equalf(t, expectedReadmePerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", + readmeFullPath, expectedReadmePerm, info.Mode().Perm(), currentUmask) } func TestCleanJoin(t *testing.T) { diff --git a/internal/plugin/installer/installer_test.go b/internal/plugin/installer/installer_test.go index 620afc183..75c22787b 100644 --- a/internal/plugin/installer/installer_test.go +++ b/internal/plugin/installer/installer_test.go @@ -34,8 +34,6 @@ func TestIsRemoteHTTPArchive(t *testing.T) { // Test with invalid extension and unreachable server assert.False(t, isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.notanarchive"), "Bad URL without valid extension should not succeed") - assert.True(t, isRemoteHTTPArchive(source), "Expected %q to be a valid archive URL", source) - assert.False(t, isRemoteHTTPArchive(source+"-not-an-extension"), "Expected media type match to fail") } diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 3f5b098e4..82401d069 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -96,16 +96,14 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { require.NoError(t, err) // ensure a VCSInstaller was returned - _, ok := i.(*VCSInstaller) - require.True(t, ok, "expected a VCSInstaller") + require.IsType(t, &VCSInstaller{}, i, "expected a VCSInstaller") - if err := Install(i); err == nil { - t.Fatal("expected error for version does not exists, got none") - } else if strings.Contains(err.Error(), "Could not resolve host: github.com") { + err = Install(i) + require.Error(t, err, "expected error for version does not exists, got none") + if strings.Contains(err.Error(), "Could not resolve host: github.com") { t.Skip("Unable to run test without Internet access") - } else { - require.EqualErrorf(t, err, fmt.Sprintf("requested version %q does not exist for plugin %q", version, source), "expected error for version does not exists") } + require.EqualErrorf(t, err, fmt.Sprintf("requested version %q does not exist for plugin %q", version, source), "expected error for version does not exists") } func TestVCSInstallerUpdate(t *testing.T) { ensure.HelmHome(t) @@ -116,19 +114,16 @@ func TestVCSInstallerUpdate(t *testing.T) { require.NoError(t, err) // ensure a VCSInstaller was returned - _, ok := i.(*VCSInstaller) - require.True(t, ok, "expected a VCSInstaller") + require.IsType(t, &VCSInstaller{}, i, "expected a VCSInstaller") require.EqualErrorf(t, Update(i), "plugin does not exist", "expected error for plugin does not exist") // Install plugin before update - if err := Install(i); err != nil { - if strings.Contains(err.Error(), "Could not resolve host: github.com") { - t.Skip("Unable to run test without Internet access") - } else { - t.Fatal(err) - } + err = Install(i) + if err != nil && strings.Contains(err.Error(), "Could not resolve host: github.com") { + t.Skip("Unable to run test without Internet access") } + require.NoError(t, err) // Test FindSource method for positive result pluginInfo, err := FindSource(i.Path()) diff --git a/internal/plugin/subprocess_commands_test.go b/internal/plugin/subprocess_commands_test.go index b2ac19c02..7505bf343 100644 --- a/internal/plugin/subprocess_commands_test.go +++ b/internal/plugin/subprocess_commands_test.go @@ -16,7 +16,6 @@ limitations under the License. package plugin import ( - "reflect" "runtime" "testing" @@ -39,7 +38,7 @@ func TestPrepareCommand(t *testing.T) { cmd, args, err := PrepareCommands(platformCommand, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandExtraArgs(t *testing.T) { @@ -111,7 +110,7 @@ func TestPrepareCommands(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsExtraArgs(t *testing.T) { @@ -132,7 +131,7 @@ func TestPrepareCommandsExtraArgs(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, extraArgs, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, expectedArgs), "Expected %v, got %v", expectedArgs, args) + require.Equalf(t, expectedArgs, args, "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoArch(t *testing.T) { @@ -149,7 +148,7 @@ func TestPrepareCommandsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoOsNoArch(t *testing.T) { @@ -166,7 +165,7 @@ func TestPrepareCommandsNoOsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoMatch(t *testing.T) { @@ -206,7 +205,7 @@ func TestPrepareCommandsExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, expectedArgs), "Expected %v, got %v", expectedArgs, args) + require.Equalf(t, expectedArgs, args, "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoExpand(t *testing.T) { @@ -223,5 +222,5 @@ func TestPrepareCommandsNoExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, false, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - require.Truef(t, reflect.DeepEqual(args, cmdArgs), "Expected %v, got %v", cmdArgs, args) + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index deb9426ce..6cf529bff 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -143,7 +143,6 @@ metadata: // This test will fail if 'six' or 'seven' was added. assert.Len(t, generic, 2) - assert.Len(t, hs, 4) for _, out := range hs { diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index 547419e17..db976a45b 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -148,28 +148,22 @@ func TestResolve(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { l, err := r.Resolve(tt.req, repoNames) - if err != nil { - if tt.err { - return - } + if tt.err { + require.Error(t, err) + } else { require.NoError(t, err) - } + h, err := HashReq(tt.req, tt.expect.Dependencies) + require.NoError(t, err) + assert.Equal(t, l.Digest, h, "%q: hashes don't match.", tt.name) - if tt.err { - require.Failf(t, "Expected error in test %q", tt.name) + // Check fields. + require.Len(t, l.Dependencies, len(tt.req), "%s: wrong number of dependencies in lock", tt.name) + d0 := l.Dependencies[0] + e0 := tt.expect.Dependencies[0] + assert.Equal(t, e0.Name, d0.Name, tt.name) + assert.Equal(t, e0.Repository, d0.Repository, tt.name) + assert.Equal(t, e0.Version, d0.Version, tt.name) } - - h, err := HashReq(tt.req, tt.expect.Dependencies) - require.NoError(t, err) - assert.Equal(t, l.Digest, h, "%q: hashes don't match.", tt.name) - - // Check fields. - assert.Len(t, l.Dependencies, len(tt.req), "%s: wrong number of dependencies in lock", tt.name) - d0 := l.Dependencies[0] - e0 := tt.expect.Dependencies[0] - assert.Equal(t, e0.Name, d0.Name, tt.name) - assert.Equal(t, e0.Repository, d0.Repository, tt.name) - assert.Equal(t, e0.Version, d0.Version, tt.name) }) } } @@ -280,20 +274,16 @@ func TestGetLocalPath(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p, err := GetLocalPath(tt.repo, tt.chartpath) - if err != nil { - if tt.err { - return - } - require.NoError(t, err) - } if tt.err { - require.Failf(t, "Expected error in test %q", tt.name) - } - expect := tt.expect - if runtime.GOOS == "windows" { - expect = tt.winExpect + require.Error(t, err) + } else { + require.NoError(t, err) + if runtime.GOOS == "windows" { + assert.Equal(t, tt.winExpect, p, tt.name) + } else { + assert.Equal(t, tt.expect, p, tt.name) + } } - assert.Equal(t, expect, p, tt.name) }) } } From 4d9c03f51c30f851a03676a1315f492de10210e6 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 13:24:06 +0200 Subject: [PATCH 126/161] chore(pkg): refactor: finer tests conversions to testify part 2 #### Description refactor: finer tests conversions to testify in pkg/storage/driver Signed-off-by: Matthieu MOREL --- pkg/chart/v2/lint/lint_test.go | 15 +++++------ pkg/chart/v2/util/validate_name_test.go | 28 +++++++++++---------- pkg/cli/values/options_test.go | 30 +++++++++++----------- pkg/cmd/package_test.go | 30 +++++++++++----------- pkg/cmd/pull_test.go | 30 +++++++++++----------- pkg/cmd/search/search_test.go | 33 +++++++++++-------------- pkg/cmd/upgrade_test.go | 19 +++++--------- pkg/downloader/manager_test.go | 23 +++++++---------- pkg/engine/engine_test.go | 27 ++++++++------------ pkg/getter/ocigetter_test.go | 10 -------- pkg/repo/v1/index_test.go | 24 +++++++----------- pkg/storage/driver/cfgmaps_test.go | 23 ++++++++--------- pkg/storage/driver/memory_test.go | 11 +++------ pkg/storage/driver/secrets_test.go | 21 +++++++--------- pkg/storage/driver/sql_test.go | 25 ++++++++----------- pkg/storage/storage_test.go | 15 ++++++----- 16 files changed, 151 insertions(+), 213 deletions(-) diff --git a/pkg/chart/v2/lint/lint_test.go b/pkg/chart/v2/lint/lint_test.go index 1782c01d4..c4705872d 100644 --- a/pkg/chart/v2/lint/lint_test.go +++ b/pkg/chart/v2/lint/lint_test.go @@ -118,7 +118,7 @@ func TestBadValues(t *testing.T) { func TestBadCrdFile(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages - assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) + require.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } @@ -126,8 +126,7 @@ func TestBadCrdFile(t *testing.T) { func TestGoodChart(t *testing.T) { var values map[string]any m := RunAll(goodChartDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } @@ -147,13 +146,12 @@ func TestHelmCreateChart(t *testing.T) { // Note: we test with strict=true here, even though others have // strict = false. m := RunAll(createdChart, values, namespace, WithSkipSchemaValidation(true)).Messages - if ll := len(m); ll != 1 { - t.Errorf("All should have had exactly 1 error. Got %d", ll) + if !assert.Len(t, m, 1, "All should have had exactly 1 error") { for i, msg := range m { t.Logf("Message %d: %s", i, msg.Error()) } - } else if msg := m[0].Err.Error(); !strings.Contains(msg, "icon is recommended") { - t.Errorf("Unexpected lint error: %s", msg) + } else { + assert.ErrorContains(t, m[0].Err, "icon is recommended") } } @@ -196,8 +194,7 @@ func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { func TestSubChartValuesChart(t *testing.T) { var values map[string]any m := RunAll(subChartValuesDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } diff --git a/pkg/chart/v2/util/validate_name_test.go b/pkg/chart/v2/util/validate_name_test.go index cfc62a0f7..9095dc4dc 100644 --- a/pkg/chart/v2/util/validate_name_test.go +++ b/pkg/chart/v2/util/validate_name_test.go @@ -16,7 +16,11 @@ limitations under the License. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) // TestValidateReleaseName is a regression test for ValidateName // @@ -46,12 +50,11 @@ func TestValidateReleaseName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateReleaseName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateReleaseName(input) + if expectPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } @@ -80,12 +83,11 @@ func TestValidateMetadataName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateMetadataName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateMetadataName(input) + if expectPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index 40590f33f..6debb693e 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -215,19 +215,17 @@ func TestReadFile(t *testing.T) { got, err := readFile(actualFilePath, tt.providers) require.NoError(t, err, "readFile() expected no error for stdin") assert.Equal(t, testData, got) - return - } - - // Regular test cases - got, err := readFile(actualFilePath, tt.providers) - if tt.expectError { - assert.Error(t, err) - return - } - require.NoError(t, err) - - if tt.expectedData != nil { - assert.Equal(t, tt.expectedData, got) + } else { + // Regular test cases + got, err := readFile(actualFilePath, tt.providers) + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + if tt.expectedData != nil { + assert.Equal(t, tt.expectedData, got) + } + } } }) } @@ -356,10 +354,10 @@ func TestMergeValuesCLI(t *testing.T) { got, err := tt.opts.MergeValues(getter.Providers{}) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, got) } - require.NoError(t, err) - assert.Equal(t, tt.expected, got) }) } } diff --git a/pkg/cmd/package_test.go b/pkg/cmd/package_test.go index d78f5d88d..8b19faf08 100644 --- a/pkg/cmd/package_test.go +++ b/pkg/cmd/package_test.go @@ -139,24 +139,22 @@ func TestPackage(t *testing.T) { } } _, _, err = executeActionCommand(strings.Join(cmd, " ")) - - if err != nil { - if tt.err && re.MatchString(err.Error()) { - return + if tt.err { + require.Error(t, err) + require.True(t, re.MatchString(err.Error())) + } else { + require.NoError(t, err) + if tt.hasfile != "" { + fi, err := os.Stat(tt.hasfile) + require.NoErrorf(t, err, "%q: expected file %q", tt.name, tt.hasfile) + assert.NotEqualf(t, 0, fi.Size(), "%q: file %q has zero bytes.", tt.name, tt.hasfile) } - t.Fatalf("%q: expected error %q, got %q", tt.name, tt.expect, err) - } - if tt.hasfile != "" { - fi, err := os.Stat(tt.hasfile) - require.NoErrorf(t, err, "%q: expected file %q", tt.name, tt.hasfile) - assert.NotEqualf(t, 0, fi.Size(), "%q: file %q has zero bytes.", tt.name, tt.hasfile) - } - - if v, ok := tt.flags["sign"]; ok && v == "1" { - fi, err := os.Stat(tt.hasfile + ".prov") - require.NoErrorf(t, err, "%q: expected provenance file", tt.name) - assert.NotEqualf(t, 0, fi.Size(), "%q: provenance file is empty", tt.name) + if v, ok := tt.flags["sign"]; ok && v == "1" { + fi, err := os.Stat(tt.hasfile + ".prov") + require.NoErrorf(t, err, "%q: expected provenance file", tt.name) + assert.NotEqualf(t, 0, fi.Size(), "%q: provenance file is empty", tt.name) + } } }) } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index 352c36a29..d0371710b 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -237,25 +237,23 @@ func TestPullCmd(t *testing.T) { require.NoError(t, os.MkdirAll(file, 0o755)) } _, out, err := executeActionCommand(cmd) - if err != nil { - if tt.wantError { - if tt.wantErrorMsg != "" && tt.wantErrorMsg != err.Error() { - t.Fatalf("Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) - } - return + if tt.wantError { + if tt.wantErrorMsg != "" { + require.EqualError(t, err, tt.wantErrorMsg, "Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) } - t.Fatalf("%q reported error: %s", tt.name, err) - } + } else { + require.NoError(t, err) - if tt.expectVerify { - outString := helmTestKeyOut + tt.expectSha + "\n" - assert.Equal(t, outString, out, "%q: expected verification output %q, got %q", tt.name, outString, out) - } + if tt.expectVerify { + outString := helmTestKeyOut + tt.expectSha + "\n" + assert.Equal(t, outString, out, "%q: expected verification output %q, got %q", tt.name, outString, out) + } - ef := filepath.Join(outdir, tt.expectFile) - fi, err := os.Stat(ef) - require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) - assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) + ef := filepath.Join(outdir, tt.expectFile) + fi, err := os.Stat(ef) + require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) + assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) + } }) } } diff --git a/pkg/cmd/search/search_test.go b/pkg/cmd/search/search_test.go index f8c9504d1..e45386947 100644 --- a/pkg/cmd/search/search_test.go +++ b/pkg/cmd/search/search_test.go @@ -232,26 +232,21 @@ func TestSearchByName(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { charts, err := i.Search(tt.query, 100, tt.regexp) - if err != nil { - if tt.fail { - require.ErrorContains(t, err, tt.failMsg) - return - } - t.Fatalf("%s: %s", tt.name, err) - } - // Give us predictably ordered results. - SortScore(charts) + if tt.fail { + require.ErrorContains(t, err, tt.failMsg) + } else { + require.NoError(t, err) // Give us predictably ordered results. + SortScore(charts) - l := len(charts) - require.Lenf(t, tt.expect, l, "Expected %d result, got %d", len(tt.expect), l) - // For empty result sets, just keep going. - if l == 0 { - return - } - - for i, got := range charts { - ex := tt.expect[i] - assert.Equalf(t, got.Name, ex.Name, "[%d]: Expected name %q, got %q", i, ex.Name, got.Name) + l := len(tt.expect) + require.Len(t, charts, len(tt.expect)) + // For empty result sets, just keep going. + if l != 0 { + for i, got := range charts { + ex := tt.expect[i] + assert.Equalf(t, got.Name, ex.Name, "[%d]: Expected name %q, got %q", i, ex.Name, got.Name) + } + } } }) } diff --git a/pkg/cmd/upgrade_test.go b/pkg/cmd/upgrade_test.go index 1c1823199..5aba7b11b 100644 --- a/pkg/cmd/upgrade_test.go +++ b/pkg/cmd/upgrade_test.go @@ -22,7 +22,6 @@ import ( "net/http/httptest" "os" "path/filepath" - "reflect" "testing" "time" @@ -201,9 +200,9 @@ func TestUpgradeDependencyUpdateOCINoPanic(t *testing.T) { w.Header().Set("Docker-Distribution-API-Version", "registry/2.0") if r.URL.Path == "/v2/" { w.WriteHeader(http.StatusOK) - return + } else { + w.WriteHeader(http.StatusNotFound) } - w.WriteHeader(http.StatusNotFound) })) defer srv.Close() @@ -224,23 +223,17 @@ func TestUpgradeDependencyUpdateOCINoPanic(t *testing.T) { }}, }, } - if err := chartutil.SaveDir(parent, tmp); err != nil { - t.Fatalf("Error creating chart: %v", err) - } + require.NoError(t, chartutil.SaveDir(parent, tmp), "Error creating chart") chartPath := filepath.Join(tmp, parent.Metadata.Name) // SaveDir writes only resolved subcharts (Chart.Dependencies()), not the // declared Metadata.Dependencies, so create the empty charts/ directory // explicitly to make the "dependency missing from charts/" state concrete. - if err := os.MkdirAll(filepath.Join(chartPath, "charts"), 0o755); err != nil { - t.Fatalf("Error creating charts dir: %v", err) - } + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "charts"), 0o755), "Error creating charts dir") // The command must return an error (registry rejects the lookup), not panic. _, _, err := executeActionCommandC(storageFixture(), fmt.Sprintf("upgrade --dependency-update --plain-http oci-parent '%s'", chartPath)) - if err == nil { - t.Fatal("expected an error resolving the OCI dependency, got nil") - } + require.Error(t, err, "expected an error resolving the OCI dependency, got nil") } func TestUpgradeWithValue(t *testing.T) { @@ -471,7 +464,7 @@ func TestUpgradeInstallWithLabels(t *testing.T) { updatedRel, err := releaserToV1Release(updatedReli) require.NoError(t, err) - assert.Truef(t, reflect.DeepEqual(updatedRel.Labels, expectedLabels), "Expected {%v}, got {%v}", expectedLabels, updatedRel.Labels) + assert.Equal(t, expectedLabels, updatedRel.Labels) } func prepareMockReleaseWithSecret(t *testing.T, releaseName string) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 00cb5b668..e40bbbac1 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -20,7 +20,6 @@ import ( "io/fs" "os" "path/filepath" - "reflect" "testing" "time" @@ -168,19 +167,16 @@ func TestGetRepoNames(t *testing.T) { } for _, tt := range tests { - l, err := m.resolveRepoNames(tt.req) - if err != nil { + t.Run(tt.name, func(t *testing.T) { + l, err := m.resolveRepoNames(tt.req) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + // m1 and m2 are the maps we want to compare + assert.Equal(t, l, tt.expect, "%s: expected map %v, got %v", tt.name, l, tt.name) } - t.Fatal(err) - } - - require.False(t, tt.err, "Expected error in test %q", tt.name) - - // m1 and m2 are the maps we want to compare - eq := reflect.DeepEqual(l, tt.expect) - assert.True(t, eq, "%s: expected map %v, got %v", tt.name, l, tt.name) + }) } } @@ -479,8 +475,7 @@ func TestErrRepoNotFound_Error(t *testing.T) { e := ErrRepoNotFound{ Repos: tt.fields.Repos, } - got := e.Error() - assert.EqualErrorf(t, e, tt.want, "Error() = %v, want %v", got, tt.want) + assert.EqualError(t, e, tt.want) }) } } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index ecc1eee3b..1f3096366 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -78,8 +78,7 @@ func TestFuncMap(t *testing.T) { // Test for Engine-specific template functions. expect := []string{"include", "required", "tpl", "toYaml", "fromYaml", "toToml", "fromToml", "toJson", "fromJson", "lookup"} for _, f := range expect { - _, ok := fns[f] - assert.Truef(t, ok, "Expected add-on function %q", f) + assert.Containsf(t, fns, f, "Expected add-on function %q", f) } } @@ -412,8 +411,7 @@ func TestParseErrors(t *testing.T) { } _, err := new(Engine).render(t.Context(), tplsUndefinedFunction) require.Error(t, err, "Expected failures while rendering") - expected := `parse error at (undefined_function:1): function "foo" not defined` - assert.EqualError(t, err, expected) + assert.EqualError(t, err, `parse error at (undefined_function:1): function "foo" not defined`) } func TestExecErrors(t *testing.T) { @@ -887,9 +885,8 @@ func TestRenderRecursionLimit(t *testing.T) { expectErr := "rendering template has a nested reference name: recursion: unable to execute template" _, err := Render(c, v) - if err == nil || !strings.HasSuffix(err.Error(), expectErr) { - t.Errorf("Expected err with suffix: %s", expectErr) - } + require.Error(t, err) + assert.True(t, strings.HasSuffix(err.Error(), expectErr), "Expected err with suffix: %s", expectErr) // calling the same function many times is ok times := 4000 @@ -1261,18 +1258,14 @@ func TestRenderCustomTemplateFuncs(t *testing.T) { require.NoError(t, err) // Expected output should be "hello!!!". - expected := "hello!!!" - key := "CustomFunc/templates/manifest" - if rendered, ok := out[key]; !ok || rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + rendered, ok := out["CustomFunc/templates/manifest"] + require.True(t, ok) + assert.Equal(t, "hello!!!", rendered) // Verify that the rendered template used the custom "upper" function. - expected = "custom:hello" - key = "CustomFunc/templates/override" - if rendered, ok := out[key]; !ok || rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + rendered, ok = out["CustomFunc/templates/override"] + require.True(t, ok) + assert.Equal(t, "custom:hello", rendered) } func TestTraceableError_SimpleForm(t *testing.T) { diff --git a/pkg/getter/ocigetter_test.go b/pkg/getter/ocigetter_test.go index dfcc74890..5e7f01420 100644 --- a/pkg/getter/ocigetter_test.go +++ b/pkg/getter/ocigetter_test.go @@ -55,23 +55,14 @@ func TestOCIGetter(t *testing.T) { og, ok := g.(*OCIGetter) require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") - assert.Equal(t, "I", og.opts.username, "Expected NewOCIGetter to contain %q as the username, got %q", "I", og.opts.username) - assert.Equal(t, "Am", og.opts.password, "Expected NewOCIGetter to contain %q as the password, got %q", "Am", og.opts.password) - assert.Equal(t, pub, og.opts.certFile, "Expected NewOCIGetter to contain %q as the public key file, got %q", pub, og.opts.certFile) - assert.Equal(t, priv, og.opts.keyFile, "Expected NewOCIGetter to contain %q as the private key file, got %q", priv, og.opts.keyFile) - assert.Equal(t, ca, og.opts.caFile, "Expected NewOCIGetter to contain %q as the CA file, got %q", ca, og.opts.caFile) - assert.Equal(t, timeout, og.opts.timeout, "Expected NewOCIGetter to contain %s as Timeout flag, got %s", timeout, og.opts.timeout) - assert.Equal(t, transport, og.opts.transport, "Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) - assert.Equal(t, plainHTTP, og.opts.plainHTTP, "Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) - assert.Equal(t, insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS, "Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) // Test if setting registryClient is being passed to the ops @@ -84,7 +75,6 @@ func TestOCIGetter(t *testing.T) { require.NoError(t, err) og, ok = g.(*OCIGetter) require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") - assert.Equal(t, registryClient, og.opts.registryClient, "Expected NewOCIGetter to contain %p as RegistryClient, got %p", registryClient, og.opts.registryClient) } diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 88aed14d7..09fc7de8a 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -116,9 +116,8 @@ func TestIndexFile(t *testing.T) { assert.Equalf(t, "0.2.0", v, "Unexpected first version: %s", v) cv, err := i.Get("setter", "0.1.9") - if err == nil && !strings.Contains(cv.Version, "0.1.9") { - t.Errorf("Unexpected version: %s", cv.Version) - } + require.NoError(t, err) + assert.Contains(t, cv.Version, "0.1.9", "Unexpected version: %s", cv.Version) cv, err = i.Get("setter", "0.1.9+alpha") require.NoError(t, err, "Expected version: 0.1.9+alpha") @@ -304,9 +303,8 @@ func verifyLocalIndex(t *testing.T, i *IndexFile) { require.Equalf(t, 1, l, "'alpine' should have 1 chart, got %d", l) nginx, ok := i.Entries["nginx"] - if !ok || len(nginx) != 2 { - t.Fatal("Expected 2 nginx entries") - } + require.True(t, ok) + require.Len(t, nginx, 2, "Expected 2 nginx entries") expects := []*ChartVersion{ { @@ -507,18 +505,14 @@ func TestIgnoreSkippableChartValidationError(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { result := ignoreSkippableChartValidationError(tc.Input) - - if tc.Input == nil { + switch { + case tc.Input == nil: assert.NoError(t, result, "expected nil result for nil input") - return - } - - if tc.ErrorSkipped { + case tc.ErrorSkipped: assert.NoError(t, result, "expected nil result for skipped error") - return + default: + assert.ErrorIs(t, tc.Input, result, "expected the result equal to input") } - - assert.ErrorIs(t, tc.Input, result, "expected the result equal to input") }) } } diff --git a/pkg/storage/driver/cfgmaps_test.go b/pkg/storage/driver/cfgmaps_test.go index e36aecce8..b8449f67e 100644 --- a/pkg/storage/driver/cfgmaps_test.go +++ b/pkg/storage/driver/cfgmaps_test.go @@ -16,7 +16,6 @@ package driver import ( "encoding/base64" "encoding/json" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -46,7 +45,7 @@ func TestConfigMapGet(t *testing.T) { got, err := cfgmaps.Get(key) require.NoError(t, err, "Failed to get release") // compare fetched release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestUncompressedConfigMapGet(t *testing.T) { @@ -70,7 +69,7 @@ func TestUncompressedConfigMapGet(t *testing.T) { got, err := cfgmaps.Get(key) require.NoError(t, err, "Failed to get release") // compare fetched release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func convertReleaserToV1(t *testing.T, rel release.Releaser) *rspb.Release { @@ -105,7 +104,7 @@ func TestConfigMapList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deleted") - assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -114,7 +113,7 @@ func TestConfigMapList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deployed") - assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -123,13 +122,11 @@ func TestConfigMapList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list superseded") - assert.Len(t, ssd, 2, "Expected 2 superseded, got %d", len(ssd)) + assert.Len(t, ssd, 2, "Expected 2 superseded") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) - _, ok = rls.Labels["key1"] - require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestConfigMapQuery(t *testing.T) { @@ -144,7 +141,7 @@ func TestConfigMapQuery(t *testing.T) { rls, err := cfgmaps.Query(map[string]string{"status": "deployed"}) require.NoError(t, err, "Failed to query") - assert.Len(t, rls, 2, "Expected 2 results, got %d", len(rls)) + assert.Len(t, rls, 2, "Expected 2 results") _, err = cfgmaps.Query(map[string]string{"name": "notExist"}) assert.ErrorIs(t, err, ErrReleaseNotFound) @@ -167,7 +164,7 @@ func TestConfigMapCreate(t *testing.T) { require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestConfigMapUpdate(t *testing.T) { @@ -210,7 +207,7 @@ func TestConfigMapDelete(t *testing.T) { // perform the delete rls, err := cfgmaps.Delete(key) require.NoError(t, err, "Failed to delete release with key %q", key) - assert.Truef(t, reflect.DeepEqual(rel, rls), "Expected {%v}, got {%v}", rel, rls) + assert.Equalf(t, rel, rls, "Expected {%v}, got {%v}", rel, rls) _, err = cfgmaps.Get(key) assert.ErrorIs(t, err, ErrReleaseNotFound) } diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 7a8d4cb3e..c0eff3cf9 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -18,7 +18,6 @@ package driver import ( "fmt" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -112,7 +111,7 @@ func TestMemoryList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deployed releases") - assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := ts.List(func(rel release.Releaser) bool { @@ -121,7 +120,7 @@ func TestMemoryList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list superseded releases") - assert.Len(t, ssd, 6, "Expected 6 superseded, got %d", len(ssd)) + assert.Len(t, ssd, 6, "Expected 6 superseded") // list all deleted releases del, err := ts.List(func(rel release.Releaser) bool { @@ -210,7 +209,7 @@ func TestMemoryUpdate(t *testing.T) { r, err := ts.Get(tt.key) require.NoError(t, err, "Failed to get") - require.Truef(t, reflect.DeepEqual(r, tt.rls), "Expected %v, actual %v\n", tt.rls, r) + require.Equalf(t, r, tt.rls, "Expected %v, actual %v\n", tt.rls, r) } } } @@ -256,10 +255,8 @@ func TestMemoryDelete(t *testing.T) { ts.SetNamespace("") end, err := ts.Query(map[string]string{"status": "deployed"}) require.NoError(t, err, "Query failed") - endLen := len(end) - if startLen-2 != endLen { - t.Errorf("expected end to be %d instead of %d", startLen-2, endLen) + if !assert.Len(t, end, startLen-2) { for _, ee := range end { rac, err := release.NewAccessor(ee) require.NoError(t, err, "unable to get release accessor") diff --git a/pkg/storage/driver/secrets_test.go b/pkg/storage/driver/secrets_test.go index 8cc3f390d..b53f17ad9 100644 --- a/pkg/storage/driver/secrets_test.go +++ b/pkg/storage/driver/secrets_test.go @@ -16,7 +16,6 @@ package driver import ( "encoding/base64" "encoding/json" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -46,7 +45,7 @@ func TestSecretGet(t *testing.T) { got, err := secrets.Get(key) require.NoError(t, err, "Failed to get release") // compare fetched release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestUNcompressedSecretGet(t *testing.T) { @@ -70,7 +69,7 @@ func TestUNcompressedSecretGet(t *testing.T) { got, err := secrets.Get(key) require.NoError(t, err, "Failed to get release") // compare fetched release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestSecretList(t *testing.T) { @@ -90,7 +89,7 @@ func TestSecretList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deleted") - assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := secrets.List(func(rel release.Releaser) bool { @@ -99,7 +98,7 @@ func TestSecretList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deployed") - assert.Len(t, dpl, 2, "Expected 2 deployed, got %d", len(dpl)) + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := secrets.List(func(rel release.Releaser) bool { @@ -108,13 +107,11 @@ func TestSecretList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list superseded") - assert.Len(t, ssd, 2, "Expected 2 superseded, got %d", len(ssd)) + require.Len(t, ssd, 2, "Expected 2 superseded") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) - _, ok = rls.Labels["key1"] - require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSecretQuery(t *testing.T) { @@ -152,7 +149,7 @@ func TestSecretCreate(t *testing.T) { require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestSecretUpdate(t *testing.T) { @@ -195,7 +192,7 @@ func TestSecretDelete(t *testing.T) { // perform the delete rls, err := secrets.Delete(key) require.NoError(t, err, "Failed to delete release with key %q", key) - assert.Truef(t, reflect.DeepEqual(rel, rls), "Expected {%v}, got {%v}", rel, rls) + assert.Equalf(t, rel, rls, "Expected {%v}, got {%v}", rel, rls) _, err = secrets.Get(key) assert.ErrorIs(t, err, ErrReleaseNotFound) } diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index adcc780aa..044e9df7b 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -99,7 +99,7 @@ func TestSQLGet(t *testing.T) { got, err := sqlDriver.Get(key) require.NoError(t, err, "Failed to get release") - assert.Truef(t, reflect.DeepEqual(rel, got), "Expected release {%v}, got {%v}", rel, got) + assert.Equalf(t, rel, got, "Expected release {%v}, got {%v}", rel, got) assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } @@ -151,7 +151,7 @@ func TestSQLList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deleted") - assert.Len(t, del, 2, "Expected 2 deleted, got %d:\n%v\n", len(del), del) + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -160,7 +160,7 @@ func TestSQLList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list deployed") - assert.Len(t, dpl, 2, "Expected 2 deployed, got %d:\n%v\n", len(dpl), dpl) + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -169,15 +169,13 @@ func TestSQLList(t *testing.T) { }) // check require.NoError(t, err, "Failed to list superseded") - assert.Len(t, ssd, 2, "Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd) + require.Len(t, ssd, 2, "Expected 2 superseded") require.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - require.True(t, ok, "Expected 'name' label in results, actual %v", rls.Labels) - _, ok = rls.Labels["key1"] - require.True(t, ok, "Expected 'key1' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSqlCreate(t *testing.T) { @@ -414,18 +412,15 @@ func TestSqlQuery(t *testing.T) { require.NoError(t, err, "failed to query for deployed smug-pigeon release") for _, res := range results { - assert.Truef(t, reflect.DeepEqual(res, deployedRelease), "Expected release {%v}, got {%v}", deployedRelease, res) + assert.Equalf(t, res, deployedRelease, "Expected release {%v}, got {%v}", deployedRelease, res) } results, err = sqlDriver.Query(labelSetAll) require.NoError(t, err, "failed to query release history for smug-pigeon") - - assert.Len(t, results, 2, "expected a resultset of size 2, got %d", len(results)) + assert.Len(t, results, 2, "expected a resultset of size 2") for _, res := range results { - if !reflect.DeepEqual(res, deployedRelease) && !reflect.DeepEqual(res, supersededRelease) { - t.Errorf("Expected release {%v} or {%v}, got {%v}", deployedRelease, supersededRelease, res) - } + assert.False(t, !reflect.DeepEqual(res, deployedRelease) && !reflect.DeepEqual(res, supersededRelease), "Expected release {%v} or {%v}, got {%v}", deployedRelease, supersededRelease, res) } assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") @@ -495,7 +490,7 @@ func TestSqlDelete(t *testing.T) { assert.NoErrorf(t, err, "sql expectations weren't met") require.NoError(t, err, "failed to delete release with key %q", key) - assert.Truef(t, reflect.DeepEqual(rel, deletedRelease), "Expected release {%v}, got {%v}", rel, deletedRelease) + assert.Equalf(t, rel, deletedRelease, "Expected release {%v}, got {%v}", rel, deletedRelease) } func mockGetReleaseCustomLabels(mock sqlmock.Sqlmock, key string, namespace string, labels map[string]string) { diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 821eccb81..58cb56776 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -20,7 +20,6 @@ import ( "context" "errors" "log/slog" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -49,7 +48,7 @@ func TestStorageCreate(t *testing.T) { require.NoError(t, err, "QueryRelease") // verify the fetched and created release are the same - require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) } func TestStorageUpdate(t *testing.T) { @@ -74,7 +73,7 @@ func TestStorageUpdate(t *testing.T) { require.NoError(t, err, "QueryRelease") // verify updated and fetched releases are the same. - require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) } func TestStorageDelete(t *testing.T) { @@ -99,7 +98,7 @@ func TestStorageDelete(t *testing.T) { require.NoError(t, err, "DeleteRelease") // verify updated and fetched releases are the same. - require.Truef(t, reflect.DeepEqual(rls, res), "Expected %v, got %v", rls, res) + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) hist, err := storage.History(rls.Name) require.NoError(t, err) @@ -348,12 +347,12 @@ func TestStorageRemoveLeastRecent(t *testing.T) { require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) - if len(rhist) != storage.MaxHistory { + if !assert.Len(t, rhist, storage.MaxHistory) { for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } - t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(rhist)) } + require.Len(t, rhist, storage.MaxHistory) // We expect the existing records to be 3, 4, and 5. for i, item := range rhist { @@ -392,14 +391,14 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { // (the only deployed release), to still exist hist, err := storage.History(name) require.NoError(t, err) - if len(hist) != storage.MaxHistory { + if !assert.Len(t, hist, storage.MaxHistory) { rhist, err := releaseListToV1List(hist) require.NoError(t, err) for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } - t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(rhist)) } + require.Len(t, hist, storage.MaxHistory) expectedVersions := map[int]bool{ 2: true, From 9a2be11e6f1af0c89dc0988b88fd339751baa44c Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 13:24:06 +0200 Subject: [PATCH 127/161] chore(pkg): refactor: finer tests conversions to testify part 3 refactor: finer tests conversions to testify in pkg/cmd Signed-off-by: Matthieu MOREL --- pkg/action/install_test.go | 6 +- pkg/action/lint_test.go | 12 ++-- pkg/action/validate_test.go | 12 ++-- pkg/chart/common/util/coalesce_test.go | 12 ++-- pkg/chart/v2/lint/rules/chartfile_test.go | 7 +-- pkg/chart/v2/lint/rules/crds_test.go | 3 +- pkg/chart/v2/lint/rules/dependencies_test.go | 3 +- pkg/chart/v2/lint/support/message_test.go | 6 +- pkg/chart/v2/util/chartfile_test.go | 8 +-- pkg/chart/v2/util/create_test.go | 7 ++- pkg/chart/v2/util/dependencies_test.go | 2 +- pkg/cmd/completion_test.go | 13 ++--- pkg/cmd/repo_index_test.go | 4 +- pkg/cmd/repo_update_test.go | 6 +- pkg/cmd/rollback_test.go | 3 +- pkg/cmd/search_hub_test.go | 12 +--- pkg/cmd/show_test.go | 10 ++-- .../chart_downloader_windows_test.go | 14 ++--- pkg/engine/files_test.go | 9 +-- pkg/gates/gates_test.go | 2 +- pkg/getter/httpgetter_test.go | 18 +++--- pkg/kube/ready_test.go | 55 +++++++++++++++---- pkg/kube/resource_test.go | 6 +- pkg/kube/wait_test.go | 6 +- pkg/kubeenv/roundtripper_test.go | 9 ++- pkg/provenance/sign_test.go | 12 +--- pkg/pusher/ocipusher_test.go | 5 +- pkg/registry/chart_test.go | 6 +- pkg/registry/client_test.go | 4 +- pkg/registry/plugin_test.go | 7 +-- pkg/registry/registry_test.go | 14 ++--- pkg/release/v1/util/manifest_sorter_test.go | 1 - pkg/repo/v1/chartrepo_test.go | 8 +-- pkg/repo/v1/repo_test.go | 14 ++--- pkg/repo/v1/repotest/server_test.go | 9 +-- pkg/storage/driver/labels_test.go | 8 ++- pkg/storage/driver/records_test.go | 5 +- pkg/storage/driver/util_test.go | 7 +-- 38 files changed, 158 insertions(+), 187 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index da680f41a..4dbeb7c79 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -420,9 +420,7 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { req.NoError(err) is.Equal("with-notes", rel.Name) // test run can return as either 'parent\nchild' or 'child\nparent' - if !strings.Contains(rel.Info.Notes, "parent") && !strings.Contains(rel.Info.Notes, "child") { - t.Fatalf("Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes) - } + req.True(strings.Contains(rel.Info.Notes, "parent") || strings.Contains(rel.Info.Notes, "child"), "Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes) is.Equal("Install complete", rel.Info.Description) } @@ -1096,7 +1094,7 @@ func TestInstallCRDs(t *testing.T) { mockChart := buildChart(withFile(mockFile)) crdsToInstall := mockChart.CRDObjects() - assert.Len(t, crdsToInstall, 1) + require.Len(t, crdsToInstall, 1) assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) require.NoError(t, instAction.installCRDs(crdsToInstall)) } diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 5c956c682..f3fd994d7 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -106,10 +106,8 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - assert.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) - - actual := result.Errors[0].Error() - assert.EqualError(t, result.Errors[0], expectedError, "expected '%s', but got '%s'", expectedError, actual) + require.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) + assert.EqualError(t, result.Errors[0], expectedError) }) t.Run("should error out for corrupted tgz chart", func(t *testing.T) { @@ -118,10 +116,8 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - assert.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) - - actual := result.Errors[0].Error() - assert.EqualError(t, result.Errors[0], expectedEOFError, "expected '%s', but got '%s'", expectedEOFError, actual) + require.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) + assert.EqualError(t, result.Errors[0], expectedEOFError) }) } diff --git a/pkg/action/validate_test.go b/pkg/action/validate_test.go index 27097d177..8bd9f1916 100644 --- a/pkg/action/validate_test.go +++ b/pkg/action/validate_test.go @@ -132,7 +132,7 @@ func TestRequireAdoption(t *testing.T) { // Verify that a resource that lacks labels/annotations can be adopted found, err := requireAdoption(resources) require.NoError(t, err) - assert.Len(t, found, 1) + require.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) } @@ -157,7 +157,7 @@ func TestExistingResourceConflict(t *testing.T) { // Verify only existing resources are returned found, err := existingResourceConflict(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, found, 1) + require.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) @@ -242,8 +242,8 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, ownedList, 1) - assert.Len(t, unownedList, 1) + require.Len(t, ownedList, 1) + require.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) assert.Equal(t, "unowned", unownedList[0].Name) }) @@ -290,8 +290,8 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, ownedList, 1) - assert.Len(t, unownedList, 1) + require.Len(t, ownedList, 1) + require.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) assert.Equal(t, "unowned", unownedList[0].Name) }) diff --git a/pkg/chart/common/util/coalesce_test.go b/pkg/chart/common/util/coalesce_test.go index 6ef092365..e058bd996 100644 --- a/pkg/chart/common/util/coalesce_test.go +++ b/pkg/chart/common/util/coalesce_test.go @@ -372,8 +372,7 @@ func TestMergeValues(t *testing.T) { assert.True(t, ok, "Expected nested boat key to be present but it was removed") subchart := v["pequod"].(map[string]any)["ahab"].(map[string]any) - _, ok = subchart["boat"] - assert.True(t, ok, "Expected subchart boat key to be present but it was removed") + assert.Contains(t, subchart, "boat", "Expected subchart boat key to be present but it was removed") _, ok = subchart["nested"].(map[string]any)["bar"] assert.True(t, ok, "Expected subchart nested bar key to be present but it was removed") @@ -526,8 +525,7 @@ func TestMergeTables(t *testing.T) { // This is one test that is different from CoalesceTables. Because hole // is a nil value and it's not removed it's still present. - _, ok = dst["hole"] - assert.True(t, ok, "The hole no longer exists.") + assert.Contains(t, dst, "hole", "The hole no longer exists.") dst2 := map[string]any{ "name": "Ishmael", @@ -559,8 +557,7 @@ func TestMergeTables(t *testing.T) { det2, ok := dst2["details"].(map[string]any) require.Truef(t, ok, "Details is the wrong type: %v", dst2["details"]) - _, ok = det2["friends"] - assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Contains(t, det2, "friends", "Could not find your friends. Maybe you don't have any. :-(") assert.Equal(t, "pequod", dst2["boat"].(string), "Expected boat string, got %v", dst2["boat"]) assert.Equal(t, "black", dst2["hole"].(string), "Expected hole string, got %v", dst2["hole"]) assert.Nil(t, dst2["nilval"], "Expected nilvalue to have nil value but it does not") @@ -659,8 +656,7 @@ func TestCoalesceValuesEmptyMapWithNils(t *testing.T) { is.Equal("bar", data["foo"]) // "baz" should be preserved with nil value since it wasn't in chart defaults - _, ok = data["baz"] - is.True(ok, "Expected data.baz key to be present but it was removed") + is.Contains(data, "baz", "Expected data.baz key to be present but it was removed") is.Nil(data["baz"], "Expected data.baz key to be nil but it is not") } diff --git a/pkg/chart/v2/lint/rules/chartfile_test.go b/pkg/chart/v2/lint/rules/chartfile_test.go index 7c9f1c422..1cc331a74 100644 --- a/pkg/chart/v2/lint/rules/chartfile_test.go +++ b/pkg/chart/v2/lint/rules/chartfile_test.go @@ -195,7 +195,6 @@ func TestChartfile(t *testing.T) { expectedNumberOfErrorMessages := 7 require.Lenf(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - require.ErrorContains(t, msgs[0].Err, "name is required", "Unexpected message 0: %s", msgs[0].Err) require.ErrorContains(t, msgs[1].Err, "apiVersion is required. The value must be either \"v1\" or \"v2\"", "Unexpected message 1: %s", msgs[1].Err) require.ErrorContains(t, msgs[2].Err, "version '0.0.0.0' is not a valid SemVer", "Unexpected message 2: %s", msgs[2].Err) @@ -211,11 +210,7 @@ func TestChartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 4 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - + require.Len(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) require.ErrorContains(t, msgs[0].Err, "version should be of type string", "Unexpected message 0: %s", msgs[0].Err) require.ErrorContains(t, msgs[1].Err, "version '7.2445e+06' is not a valid SemVer", "Unexpected message 1: %s", msgs[1].Err) require.ErrorContains(t, msgs[2].Err, "appVersion should be of type string", "Unexpected message 2: %s", msgs[2].Err) diff --git a/pkg/chart/v2/lint/rules/crds_test.go b/pkg/chart/v2/lint/rules/crds_test.go index 7016c4d9a..d0790692f 100644 --- a/pkg/chart/v2/lint/rules/crds_test.go +++ b/pkg/chart/v2/lint/rules/crds_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/v2/lint/support" ) @@ -33,7 +34,7 @@ func TestInvalidCrdsDir(t *testing.T) { Crds(&linter) res := linter.Messages - assert.Len(t, res, 1) + require.Len(t, res, 1) assert.ErrorContains(t, res[0].Err, "not a directory") } diff --git a/pkg/chart/v2/lint/rules/dependencies_test.go b/pkg/chart/v2/lint/rules/dependencies_test.go index c800887bd..4bd7b3e37 100644 --- a/pkg/chart/v2/lint/rules/dependencies_test.go +++ b/pkg/chart/v2/lint/rules/dependencies_test.go @@ -140,8 +140,7 @@ func TestDependencies(t *testing.T) { linter := support.Linter{ChartDir: filepath.Join(tmp, c.Metadata.Name)} Dependencies(&linter) - if l := len(linter.Messages); l != 2 { - t.Errorf("expected 2 linter errors for bad chart dependencies. Got %d.", l) + if !assert.Len(t, linter.Messages, 2, "expected 2 linter errors for bad chart dependencies") { for i, msg := range linter.Messages { t.Logf("Message: %d, Error: %#v", i, msg) } diff --git a/pkg/chart/v2/lint/support/message_test.go b/pkg/chart/v2/lint/support/message_test.go index dfbc65844..6d09df688 100644 --- a/pkg/chart/v2/lint/support/message_test.go +++ b/pkg/chart/v2/lint/support/message_test.go @@ -58,11 +58,11 @@ func TestRunLinterRule(t *testing.T) { func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - require.EqualErrorf(t, m, "[ERROR] Chart.yaml: Foo", "Unexpected output: %s", m.Error()) + require.EqualError(t, m, "[ERROR] Chart.yaml: Foo") m = Message{WarningSev, "templates/", errors.New("Bar")} - require.EqualErrorf(t, m, "[WARNING] templates/: Bar", "Unexpected output: %s", m.Error()) + require.EqualError(t, m, "[WARNING] templates/: Bar") m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - assert.EqualErrorf(t, m, "[INFO] templates/rc.yaml: FooBar", "Unexpected output: %s", m.Error()) + assert.EqualError(t, m, "[INFO] templates/rc.yaml: FooBar") } diff --git a/pkg/chart/v2/util/chartfile_test.go b/pkg/chart/v2/util/chartfile_test.go index bdcb506da..981d0e131 100644 --- a/pkg/chart/v2/util/chartfile_test.go +++ b/pkg/chart/v2/util/chartfile_test.go @@ -49,12 +49,8 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) assert.Len(t, f.Keywords, 3, "Unexpected keywords") require.Len(t, f.Annotations, 2, "Unexpected annotations") - - want, got := "extravalue", f.Annotations["extrakey"] - assert.Equalf(t, want, got, "Want %q, but got %q", want, got) - - want, got = "anothervalue", f.Annotations["anotherkey"] - assert.Equalf(t, want, got, "Want %q, but got %q", want, got) + assert.Equal(t, "extravalue", f.Annotations["extrakey"]) + assert.Equal(t, "anothervalue", f.Annotations["anotherkey"]) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { diff --git a/pkg/chart/v2/util/create_test.go b/pkg/chart/v2/util/create_test.go index c85c4e3d4..69ba1336d 100644 --- a/pkg/chart/v2/util/create_test.go +++ b/pkg/chart/v2/util/create_test.go @@ -138,8 +138,11 @@ func TestValidateChartName(t *testing.T) { "abcdefghijklmnopqrstuvwxyz-_." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.": false, } { - if err := validateChartName(name); (err != nil) == shouldPass { - t.Errorf("test for %q failed", name) + err := validateChartName(name) + if shouldPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } diff --git a/pkg/chart/v2/util/dependencies_test.go b/pkg/chart/v2/util/dependencies_test.go index 2386d2c28..097663783 100644 --- a/pkg/chart/v2/util/dependencies_test.go +++ b/pkg/chart/v2/util/dependencies_test.go @@ -43,7 +43,7 @@ func TestLoadDependency(t *testing.T) { } check := func(deps []*chart.Dependency) { - assert.Len(t, deps, 2, "expected 2 dependencies, got %d", len(deps)) + require.Len(t, deps, 2, "expected 2 dependencies, got %d", len(deps)) for i, tt := range tests { assert.Equal(t, tt.Name, deps[i].Name, "expected dependency named %q, got %q", tt.Name, deps[i].Name) assert.Equal(t, tt.Version, deps[i].Version, "expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) diff --git a/pkg/cmd/completion_test.go b/pkg/cmd/completion_test.go index 219d1eed0..296ae457e 100644 --- a/pkg/cmd/completion_test.go +++ b/pkg/cmd/completion_test.go @@ -18,9 +18,9 @@ package cmd import ( "fmt" - "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -47,13 +47,10 @@ func checkFileCompletion(t *testing.T, cmdName string, shouldBePerformed bool) { testcmd := fmt.Sprintf("__complete %s ''", cmdName) _, out, err := executeActionCommandC(storage, testcmd) require.NoError(t, err) - if !strings.Contains(out, "ShellCompDirectiveNoFileComp") != shouldBePerformed { - if shouldBePerformed { - t.Errorf("Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) - } else { - t.Errorf("Did not receive directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) - } - t.Log(out) + if shouldBePerformed { + assert.NotContains(t, out, "ShellCompDirectiveNoFileComp", "Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) + } else { + assert.Contains(t, out, "ShellCompDirectiveNoFileComp", "Did not receive directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) } } diff --git a/pkg/cmd/repo_index_test.go b/pkg/cmd/repo_index_test.go index 30700749b..67984f3b7 100644 --- a/pkg/cmd/repo_index_test.go +++ b/pkg/cmd/repo_index_test.go @@ -48,10 +48,10 @@ func TestRepoIndexCmd(t *testing.T) { index, err := repo.LoadIndexFile(destIndex) require.NoError(t, err) - assert.Len(t, index.Entries, 1, "expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) + require.Len(t, index.Entries, 1, "expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) vs := index.Entries["compressedchart"] - assert.Len(t, vs, 2, "expected 2 versions, got %d: %#v", len(vs), vs) + require.Len(t, vs, 2, "expected 2 versions") expectedVersion := "0.2.0" assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) diff --git a/pkg/cmd/repo_update_test.go b/pkg/cmd/repo_update_test.go index ccd8b89c6..70b6dfbef 100644 --- a/pkg/cmd/repo_update_test.go +++ b/pkg/cmd/repo_update_test.go @@ -174,10 +174,8 @@ func TestUpdateChartsFailWithError(t *testing.T) { b := bytes.NewBuffer(nil) err = updateCharts([]*repo.ChartRepository{r1, r2}, b) require.Error(t, err, "Repo update should return error because update of repository fails and 'fail-on-repo-update-fail' flag set") - var expectedErr = "failed to update the following repositories" - var receivedErr = err.Error() - require.ErrorContains(t, err, expectedErr, "Expected error (%s) but got (%s) instead", expectedErr, receivedErr) - require.ErrorContains(t, err, invalidURL, "Expected invalid URL (%s) in error message but got (%s) instead", invalidURL, receivedErr) + require.ErrorContains(t, err, "failed to update the following repositories") + require.ErrorContains(t, err, invalidURL) got := b.String() assert.Contains(t, got, "Unable to get an update", "Repo should have failed update but instead got: %q", got) diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index ff7f314c9..aa60043aa 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -18,7 +18,6 @@ package cmd import ( "fmt" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -161,5 +160,5 @@ func TestRollbackWithLabels(t *testing.T) { updatedRel, err := releaserToV1Release(updatedReli) require.NoError(t, err) - assert.Truef(t, reflect.DeepEqual(updatedRel.Labels, labels1), "Expected {%v}, got {%v}", labels1, updatedRel.Labels) + assert.Equalf(t, updatedRel.Labels, labels1, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) } diff --git a/pkg/cmd/search_hub_test.go b/pkg/cmd/search_hub_test.go index 7b00cc295..a1612443a 100644 --- a/pkg/cmd/search_hub_test.go +++ b/pkg/cmd/search_hub_test.go @@ -46,11 +46,7 @@ func TestSearchHubCmd(t *testing.T) { storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) require.NoError(t, err) - if out != expected { - t.Error("expected and actual output did not match") - t.Log(out) - t.Log(expected) - } + assert.Equal(t, expected, out, "expected and actual output did not match") } func TestSearchHubListRepoCmd(t *testing.T) { @@ -73,11 +69,7 @@ func TestSearchHubListRepoCmd(t *testing.T) { storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) require.NoError(t, err) - if out != expected { - t.Error("expected and actual output did not match") - t.Log(out) - t.Log(expected) - } + assert.Equal(t, expected, out, "expected and actual output did not match") } func TestSearchHubOutputCompletion(t *testing.T) { diff --git a/pkg/cmd/show_test.go b/pkg/cmd/show_test.go index 3ed01d418..b7ad94d94 100644 --- a/pkg/cmd/show_test.go +++ b/pkg/cmd/show_test.go @@ -77,12 +77,10 @@ func TestShowPreReleaseChart(t *testing.T) { contentTmp, ) _, _, err := executeActionCommand(cmd) - if err != nil { - if tt.fail { - assert.ErrorContains(t, err, tt.expectedErr, "%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) - return - } - t.Errorf("%q reported error: %s", tt.name, err) + if tt.fail { + assert.ErrorContains(t, err, tt.expectedErr, "%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) + } else { + assert.NoError(t, err) } }) } diff --git a/pkg/downloader/chart_downloader_windows_test.go b/pkg/downloader/chart_downloader_windows_test.go index 2b6bea5eb..0c7a23d23 100644 --- a/pkg/downloader/chart_downloader_windows_test.go +++ b/pkg/downloader/chart_downloader_windows_test.go @@ -99,10 +99,8 @@ func TestParallelDownloadTo(t *testing.T) { // Verify the file has the expected size (should match the source file) sourceFile := "testdata/local-subchart-0.1.0.tgz" sourceInfo, err := os.Stat(sourceFile) - if err == nil && info.Size() != sourceInfo.Size() { - t.Errorf("Downloaded file size (%d bytes) doesn't match source file size (%d bytes)", - info.Size(), sourceInfo.Size()) - } + require.NoError(t, err) + assert.False(t, info.Size() != sourceInfo.Size(), "Downloaded file size doesn't match source file size") // Verify it's a valid tar.gz file by checking the magic bytes file, err := os.Open(expectedFile) @@ -110,10 +108,10 @@ func TestParallelDownloadTo(t *testing.T) { defer file.Close() // gzip magic bytes are 0x1f 0x8b magic := make([]byte, 2) - if n, err := file.Read(magic); err == nil && n == 2 { - if magic[0] != 0x1f || magic[1] != 0x8b { - t.Errorf("Downloaded file is not a valid gzip file (magic bytes: %x)", magic) - } + n, err := file.Read(magic) + require.NoError(t, err) + if n == 2 { + assert.False(t, magic[0] != 0x1f || magic[1] != 0x8b, "Downloaded file is not a valid gzip file (magic bytes: %x)", magic) } } diff --git a/pkg/engine/files_test.go b/pkg/engine/files_test.go index 6ff251aad..9fec2e132 100644 --- a/pkg/engine/files_test.go +++ b/pkg/engine/files_test.go @@ -16,6 +16,7 @@ limitations under the License. package engine import ( + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -47,10 +48,10 @@ func TestNewFiles(t *testing.T) { assert.Len(t, files, len(cases), "Expected len() = %d, got %d", len(cases), len(files)) for i, f := range cases { - got := string(files.GetBytes(f.path)) - assert.Equalf(t, got, f.data, "%d: expected %q, got %q", i, f.data, got) - got = files.Get(f.path) - assert.Equalf(t, got, f.data, "%d: expected %q, got %q", i, f.data, got) + t.Run(strconv.Itoa(i), func(t *testing.T) { + assert.Equal(t, f.data, string(files.GetBytes(f.path))) + assert.Equal(t, f.data, files.Get(f.path)) + }) } } diff --git a/pkg/gates/gates_test.go b/pkg/gates/gates_test.go index 217ee1bbe..e57f1aa8f 100644 --- a/pkg/gates/gates_test.go +++ b/pkg/gates/gates_test.go @@ -38,7 +38,7 @@ func TestError(t *testing.T) { os.Unsetenv(name) g := Gate(name) - assert.Equal(t, "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature", g.Error().Error()) + assert.EqualError(t, g.Error(), "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature") } func TestString(t *testing.T) { diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index bfde5efa8..aebb6f11c 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -122,9 +122,9 @@ func TestDownload(t *testing.T) { const expectedUserAgent = "I am Groot" basicAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if !ok || username != "username" || password != "password" { - t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) - } + assert.True(t, ok, "Expected request to use basic auth") + assert.Equal(t, "username", username) + assert.Equal(t, "password", password) assert.Equal(t, expectedUserAgent, r.UserAgent(), "Expected '%s', got '%s'", expectedUserAgent, r.UserAgent()) fmt.Fprint(w, expect) })) @@ -147,9 +147,9 @@ func TestDownload(t *testing.T) { // test with Get URL differing from withURL crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if ok || username == "username" || password == "password" { - t.Errorf("Expected request to not include but got '%v', '%s', '%s'", ok, username, password) - } + assert.False(t, ok) + assert.NotEqual(t, "username", username) + assert.NotEqual(t, "password", password) fmt.Fprint(w, expect) })) @@ -176,9 +176,9 @@ func TestDownload(t *testing.T) { // test with Get URL differing from withURL and should pass creds crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if !ok || username != "username" || password != "password" { - t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) - } + assert.True(t, ok, "Expected request to use basic auth") + assert.Equal(t, "username", username) + assert.Equal(t, "password", password) fmt.Fprint(w, expect) })) diff --git a/pkg/kube/ready_test.go b/pkg/kube/ready_test.go index 01f6db3cb..c40ad1d4d 100644 --- a/pkg/kube/ready_test.go +++ b/pkg/kube/ready_test.go @@ -165,7 +165,11 @@ func Test_ReadyChecker_IsReady_Job(t *testing.T) { require.NoError(t, err, "Failed to create Job") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -237,7 +241,11 @@ func Test_ReadyChecker_IsReady_Deployment(t *testing.T) { require.NoError(t, err, "Failed to create ReplicaSet") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -303,7 +311,11 @@ func Test_ReadyChecker_IsReady_PersistentVolumeClaim(t *testing.T) { require.NoError(t, err, "Failed to create PersistentVolumeClaim") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -369,7 +381,11 @@ func Test_ReadyChecker_IsReady_Service(t *testing.T) { require.NoError(t, err, "Failed to create Service") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -435,7 +451,11 @@ func Test_ReadyChecker_IsReady_DaemonSet(t *testing.T) { require.NoError(t, err, "Failed to create DaemonSet") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -501,7 +521,11 @@ func Test_ReadyChecker_IsReady_StatefulSet(t *testing.T) { require.NoError(t, err, "Failed to create StatefulSet") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -582,7 +606,11 @@ func Test_ReadyChecker_IsReady_ReplicationController(t *testing.T) { require.NoError(t, err, "Failed to create ReplicationController") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -646,7 +674,11 @@ func Test_ReadyChecker_IsReady_ReplicaSet(t *testing.T) { } // got, err := c.IsReady(tt.args.ctx, tt.args.resource) - assert.Equal(t, tt.wantErr, (err != nil), "IsReady() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") + } assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } @@ -1044,9 +1076,10 @@ func Test_ReadyChecker_jobReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got, err := c.jobReady(tt.args.job) - if (err != nil) != tt.wantErr { - t.Errorf("jobReady() error = %v, wantErr %v", err, tt.wantErr) - return + if tt.wantErr { + require.Error(t, err, "jobReady()") + } else { + require.NoError(t, err, "jobReady()") } assert.Equal(t, tt.want, got, "jobReady() = %v, want %v", got, tt.want) }) diff --git a/pkg/kube/resource_test.go b/pkg/kube/resource_test.go index ca41a06ed..18501d4e8 100644 --- a/pkg/kube/resource_test.go +++ b/pkg/kube/resource_test.go @@ -42,13 +42,11 @@ func TestResourceList(t *testing.T) { diff := r1.Difference(r2) assert.Len(t, diff, 1, "expected 1 result") - - assert.True(t, diff.Contains(info("foo")), "expected diff to return foo") + assert.Contains(t, diff, info("foo"), "expected diff to return foo") inter := r1.Intersect(r2) assert.Len(t, inter, 1, "expected 1 result") - - assert.True(t, inter.Contains(info("bar")), "expected intersect to return bar") + assert.Contains(t, inter, info("bar"), "expected intersect to return bar") } func TestIsMatchingInfo(t *testing.T) { diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go index 9cf1e5506..d33a12c87 100644 --- a/pkg/kube/wait_test.go +++ b/pkg/kube/wait_test.go @@ -297,8 +297,7 @@ func TestLegacyWaiter_waitForPodSuccess(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForPodSuccess(tt.obj, "foo") if tt.wantErr { - require.Error(t, err, "expected error, got none") - require.ErrorContains(t, err, tt.errMessage, "expected error to contain %q, got %q", tt.errMessage, err.Error()) + require.ErrorContains(t, err, tt.errMessage) } else { require.NoError(t, err) } @@ -384,8 +383,7 @@ func TestLegacyWaiter_waitForJob(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForJob(tt.obj, "test-job") if tt.wantErr { - require.Error(t, err, "expected error, got none") - require.ErrorContainsf(t, err, tt.errMessage, "expected error to contain %q, got %q", tt.errMessage, err.Error()) + require.ErrorContains(t, err, tt.errMessage) } else { require.NoError(t, err) assert.Equal(t, tt.wantDone, done, "got done=%v, want %v", done, tt.wantDone) diff --git a/pkg/kubeenv/roundtripper_test.go b/pkg/kubeenv/roundtripper_test.go index 6f0caf6f8..8d5b80e39 100644 --- a/pkg/kubeenv/roundtripper_test.go +++ b/pkg/kubeenv/roundtripper_test.go @@ -141,12 +141,11 @@ func TestRetryingRoundTripper_RoundTrip(t *testing.T) { if tt.expectedErr != "" { require.ErrorContains(t, err, tt.expectedErr) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedCode, resp.StatusCode) + assert.Equal(t, tt.expectedCalls, fakeRT.calls) } - require.NoError(t, err) - - assert.Equal(t, tt.expectedCode, resp.StatusCode) - assert.Equal(t, tt.expectedCalls, fakeRT.calls) }) } } diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 32253df90..ec6e6194b 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -128,9 +128,7 @@ func TestParseMessageBlock(t *testing.T) { func TestLoadKey(t *testing.T) { k, err := loadKey(testKeyfile) require.NoError(t, err) - - _, ok := k.Identities[testKeyName] - assert.Truef(t, ok, "Expected to load a key for user %q", testKeyName) + assert.Containsf(t, k.Identities, testKeyName, "Expected to load a key for user %q", testKeyName) } func TestLoadKeyRing(t *testing.T) { @@ -163,8 +161,7 @@ func TestNewFromFiles(t *testing.T) { s, err := NewFromFiles(testKeyfile, testPubfile) require.NoError(t, err) - _, ok := s.Entity.Identities[testKeyName] - assert.Truef(t, ok, "Expected to load a key for user %q", testKeyName) + assert.Containsf(t, s.Entity.Identities, testKeyName, "Expected to load a key for user %q", testKeyName) } func TestDigestFile(t *testing.T) { @@ -240,7 +237,6 @@ func TestMixedKeyringRSASigningAndVerification(t *testing.T) { } assert.True(t, hasEdDSA, "expected %s to include an Ed25519 public key", testMixedKeyring) - require.NotNil(t, signer.Entity, "expected signer entity to be loaded") require.NotNil(t, signer.Entity.PrivateKey, "expected signer private key to be loaded") assert.Equal(t, packet.PubKeyAlgoRSA, signer.Entity.PrivateKey.PubKeyAlgo, "expected RSA key") @@ -259,9 +255,7 @@ func TestMixedKeyringRSASigningAndVerification(t *testing.T) { require.NotNil(t, verification.SignedBy, "expected verification to include signer") require.NotNil(t, verification.SignedBy.PrimaryKey, "expected verification to include signer primary key") assert.Equal(t, packet.PubKeyAlgoRSA, verification.SignedBy.PrimaryKey.PubKeyAlgo, "expected verification to report RSA key") - - _, ok := verification.SignedBy.Identities[testKeyName] - assert.True(t, ok, "expected verification to be signed by %q", testKeyName) + assert.Contains(t, verification.SignedBy.Identities, testKeyName, "expected verification to be signed by %q", testKeyName) } // failSigner always fails to sign and returns an error diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index ceb61d442..b63077293 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -33,8 +33,7 @@ func TestNewOCIPusher(t *testing.T) { p, err := NewOCIPusher() require.NoError(t, err) - _, ok := p.(*OCIPusher) - require.True(t, ok, "Expected NewOCIPusher to produce an *OCIPusher") + require.IsType(t, &OCIPusher{}, p, "Expected NewOCIPusher to produce an *OCIPusher") cd := "../../testdata" join := filepath.Join @@ -196,7 +195,7 @@ func TestOCIPusher_newRegistryClient(t *testing.T) { if tt.expectError { require.Error(t, err, "Expected error but got none") if tt.errorContains != "" { - require.ErrorContainsf(t, err, tt.errorContains, "Expected error containing %q, got %q", tt.errorContains, err.Error()) + require.ErrorContains(t, err, tt.errorContains) } } else { require.NoError(t, err) diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index 95e429a0b..3edf21e38 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -232,8 +232,7 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { result := generateOCIAnnotations(testChart, nowTimeString) // Check that created annotation exists - _, ok := result[ocispec.AnnotationCreated] - assert.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) + assert.Contains(t, result, ocispec.AnnotationCreated, "%s annotation not created", ocispec.AnnotationCreated) // Verify value of created artifact in RFC3339 format _, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) @@ -243,8 +242,7 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { result = generateOCIAnnotations(testChart, "") // Check that created annotation exists - _, ok = result[ocispec.AnnotationCreated] - require.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) + require.Contains(t, result, ocispec.AnnotationCreated, "%s annotation not created", ocispec.AnnotationCreated) createdTimeAnnotation, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) require.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) diff --git a/pkg/registry/client_test.go b/pkg/registry/client_test.go index 97b7c7c4c..21604ce7e 100644 --- a/pkg/registry/client_test.go +++ b/pkg/registry/client_test.go @@ -65,9 +65,9 @@ func TestLogin_ResetsForceAttemptOAuth2_OnSuccess(t *testing.T) { if r.URL.Path == "/v2/" { // Accept either HEAD or GET w.WriteHeader(http.StatusOK) - return + } else { + http.NotFound(w, r) } - http.NotFound(w, r) })) defer srv.Close() diff --git a/pkg/registry/plugin_test.go b/pkg/registry/plugin_test.go index bb557c5b8..d51cfa0d6 100644 --- a/pkg/registry/plugin_test.go +++ b/pkg/registry/plugin_test.go @@ -78,11 +78,10 @@ func TestGetPluginName(t *testing.T) { if tt.expectErr { assert.Error(t, err, "expected error but got none") - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, pluginName) } - - require.NoError(t, err) - assert.Equal(t, tt.expected, pluginName) }) } } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 313cb861c..40ebe9687 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -376,23 +376,21 @@ func initFakeRegistryTestServer() string { if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) - return + } else { + w.Header().Set("Content-Type", ProvLayerMediaType) + w.Write(data) } - w.Header().Set("Content-Type", ProvLayerMediaType) - w.Write(data) - case "/v2/testrepo/image-index/blobs/sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55": data, err := os.ReadFile("../downloader/testdata/signtest-0.1.0.tgz") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) - return + } else { + w.Header().Set("Content-Type", ChartLayerMediaType) + w.Write(data) } - w.Header().Set("Content-Type", ChartLayerMediaType) - w.Write(data) - default: w.WriteHeader(http.StatusNotFound) } diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index 35c7a0721..da08ab169 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -143,7 +143,6 @@ metadata: // This test will fail if 'six' or 'seven' was added. assert.Len(t, generic, 2) - assert.Len(t, hs, 4) for _, out := range hs { diff --git a/pkg/repo/v1/chartrepo_test.go b/pkg/repo/v1/chartrepo_test.go index 4be2ebf73..54275e28d 100644 --- a/pkg/repo/v1/chartrepo_test.go +++ b/pkg/repo/v1/chartrepo_test.go @@ -175,9 +175,7 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { // versions of Darwin do not. As there are people developing Helm using both old and new versions of Darwin we test // for both messages. if runtime.GOOS == "darwin" { - if !strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") && !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { - t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) - } + assert.True(t, strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") || strings.Contains(err.Error(), "x509: certificate signed by unknown authority"), "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) } else { assert.ErrorContainsf(t, err, "x509: certificate signed by unknown authority", "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error") } @@ -203,7 +201,6 @@ func TestErrorFindChartInRepoURL(t *testing.T) { }) _, err := FindChartInRepoURL("http://someserver/something", "nginx", g) - require.Error(t, err, "Expected error for bad chart URL, but did not get any errors") require.ErrorContainsf(t, err, `looks like "http://someserver/something" is not a valid chart repository or cannot be reached`, "Expected error for bad chart URL, but got a different error") srv, err := startLocalServerForTests(nil) @@ -211,16 +208,13 @@ func TestErrorFindChartInRepoURL(t *testing.T) { defer srv.Close() _, err = FindChartInRepoURL(srv.URL, "nginx1", g) - require.Error(t, err, "Expected error for chart not found, but did not get any errors") require.EqualError(t, err, `chart "nginx1" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") require.ErrorIs(t, err, ChartNotFoundError{}, "error is not of correct error type structure") _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")) - require.Error(t, err, "Expected error for chart not found, but did not get any errors") require.EqualError(t, err, `chart "nginx1" version "0.1.0" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") _, err = FindChartInRepoURL(srv.URL, "chartWithNoURL", g) - require.Error(t, err, "Expected error for no chart URLs available, but did not get any errors") assert.EqualError(t, err, `chart "chartWithNoURL" has no downloadable URLs`, "Expected error for chart not found, but got a different error") } diff --git a/pkg/repo/v1/repo_test.go b/pkg/repo/v1/repo_test.go index e3373fc49..f7f5df9be 100644 --- a/pkg/repo/v1/repo_test.go +++ b/pkg/repo/v1/repo_test.go @@ -120,11 +120,8 @@ func TestRemoveRepository(t *testing.T) { ) removeRepository := "stable" - found := sampleRepository.Remove(removeRepository) - assert.Truef(t, found, "expected repository %s not found", removeRepository) - - found = sampleRepository.Has(removeRepository) - assert.Falsef(t, found, "repository %s not deleted", removeRepository) + assert.Truef(t, sampleRepository.Remove(removeRepository), "expected repository %s not found", removeRepository) + assert.Falsef(t, sampleRepository.Has(removeRepository), "repository %s not deleted", removeRepository) } func TestUpdateRepository(t *testing.T) { @@ -205,9 +202,6 @@ func TestRemoveRepositoryInvalidEntries(t *testing.T) { ) removeRepository := "stable" - found := sampleRepository.Remove(removeRepository) - assert.Truef(t, found, "expected repository %s not found", removeRepository) - - found = sampleRepository.Has(removeRepository) - assert.Falsef(t, found, "repository %s not deleted", removeRepository) + assert.Truef(t, sampleRepository.Remove(removeRepository), "expected repository %s not found", removeRepository) + assert.Falsef(t, sampleRepository.Has(removeRepository), "repository %s not deleted", removeRepository) } diff --git a/pkg/repo/v1/repotest/server_test.go b/pkg/repo/v1/repotest/server_test.go index 7008e2305..f74adb445 100644 --- a/pkg/repo/v1/repotest/server_test.go +++ b/pkg/repo/v1/repotest/server_test.go @@ -42,24 +42,25 @@ func TestServer(t *testing.T) { c, err := srv.CopyCharts("testdata/*.tgz") require.NoError(t, err) - - assert.Len(t, c, 1) - + require.Len(t, c, 1) assert.Equal(t, "examplechart-0.1.0.tgz", filepath.Base(c[0])) req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/examplechart-0.1.0.tgz", http.NoBody) require.NoError(t, err) + client := http.DefaultClient res, err := client.Do(req) require.NoError(t, err) - res.Body.Close() + res.Body.Close() assert.GreaterOrEqual(t, res.ContentLength, int64(500)) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml", http.NoBody) require.NoError(t, err) + res, err = client.Do(req) require.NoError(t, err) + data, err := io.ReadAll(res.Body) res.Body.Close() require.NoError(t, err) diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index 848ae8861..481b8c467 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -18,6 +18,8 @@ package driver import ( "testing" + + "github.com/stretchr/testify/require" ) func TestLabelsMatch(t *testing.T) { @@ -42,8 +44,8 @@ func TestLabelsMatch(t *testing.T) { } for _, tt := range tests { - if !tt.set1.match(tt.set2) && tt.expect { - t.Fatalf("Expected match '%s'\n", tt.desc) - } + t.Run(tt.desc, func(t *testing.T) { + require.False(t, !tt.set1.match(tt.set2) && tt.expect) + }) } } diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 067e31e76..22d54e6cc 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -17,7 +17,6 @@ limitations under the License. package driver import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -132,7 +131,7 @@ func TestRecordsGet(t *testing.T) { for _, tt := range tests { got := rs.Get(tt.key) - require.Truef(t, reflect.DeepEqual(tt.rec, got), "Expected %v, got %v", tt.rec, got) + require.Equal(t, tt.rec, got, "Expected %v, got %v", tt.rec, got) } } @@ -222,6 +221,6 @@ func TestRecordsReplace(t *testing.T) { for _, tt := range tests { got := rs.Replace(tt.key, tt.rec) - require.Truef(t, reflect.DeepEqual(tt.expected, got), "Expected %v, got %v", tt.expected, got) + require.Equalf(t, tt.expected, got, "Expected %v, got %v", tt.expected, got) } } diff --git a/pkg/storage/driver/util_test.go b/pkg/storage/driver/util_test.go index 7074f252a..5dda3cd1f 100644 --- a/pkg/storage/driver/util_test.go +++ b/pkg/storage/driver/util_test.go @@ -14,7 +14,6 @@ limitations under the License. package driver import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -22,7 +21,7 @@ import ( func TestGetSystemLabel(t *testing.T) { output := GetSystemLabels() - assert.Truef(t, reflect.DeepEqual(systemLabels, output), "Expected {%v}, got {%v}", systemLabels, output) + assert.Equalf(t, systemLabels, output, "Expected {%v}, got {%v}", systemLabels, output) } func TestIsSystemLabel(t *testing.T) { @@ -69,7 +68,7 @@ func TestFilterSystemLabels(t *testing.T) { } for _, test := range tests { output := filterSystemLabels(test[0]) - assert.Truef(t, reflect.DeepEqual(test[1], output), "Expected {%v}, got {%v}", test[1], output) + assert.Equalf(t, test[1], output, "Expected {%v}, got {%v}", test[1], output) } } @@ -101,6 +100,6 @@ func TestContainsSystemLabels(t *testing.T) { } for _, test := range tests { output := ContainsSystemLabels(test.input) - assert.Truef(t, reflect.DeepEqual(test.output, output), "Expected {%v}, got {%v}", test.output, output) + assert.Equalf(t, test.output, output, "Expected {%v}, got {%v}", test.output, output) } } From 828d01a8786162987482408b7803ceb3f3c176ac Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 13:24:06 +0200 Subject: [PATCH 128/161] chore(pkg): refactor: finer tests conversions to testify part 1 refactor: finer tests conversions to testify in pkg/strvals Signed-off-by: Matthieu MOREL --- pkg/action/upgrade_test.go | 25 +-- pkg/chart/v2/lint/rules/template_test.go | 29 ++-- pkg/chart/v2/loader/load_test.go | 37 ++--- pkg/downloader/chart_downloader_test.go | 65 ++++---- pkg/kube/client_test.go | 22 ++- pkg/strvals/literal_parser_test.go | 81 ++++------ pkg/strvals/parser_test.go | 189 +++++++++-------------- 7 files changed, 177 insertions(+), 271 deletions(-) diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index b7e25206d..53419b6a8 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -252,11 +252,8 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -320,11 +317,8 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { // Now get the upgraded release updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -383,11 +377,8 @@ func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -523,11 +514,8 @@ func TestUpgradeRelease_Labels(t *testing.T) { // Now make sure it is actually upgraded and labels were merged updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) @@ -536,11 +524,8 @@ func TestUpgradeRelease_Labels(t *testing.T) { // Now make sure it is suppressed release still contains original labels initialResi, err := upAction.cfg.Releases.Get(res.Name, 1) req.NoError(err) + req.NotNil(initialResi, "Initial Release is nil") - if initialResi == nil { - is.Fail("Updated Release is nil") - return - } initialRes, err := releaserToV1Release(initialResi) req.NoError(err) is.Equal(common.StatusSuperseded, initialRes.Info.Status) diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index 37a33a7eb..ab78450b9 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -171,8 +171,11 @@ func TestValidateMetadataName(t *testing.T) { } for _, tt := range tests { t.Run(fmt.Sprintf("%s/%s", tt.obj.Kind, tt.obj.Metadata.Name), func(t *testing.T) { - if err := validateMetadataName(tt.obj); (err != nil) != tt.wantErr { - t.Errorf("validateMetadataName() error = %v, wantErr %v", err, tt.wantErr) + err := validateMetadataName(tt.obj) + if tt.wantErr { + require.Error(t, err, "validateMetadataName()") + } else { + require.NoError(t, err, "validateMetadataName()") } }) } @@ -210,12 +213,12 @@ func TestDeprecatedAPIFails(t *testing.T) { namespace, values, TemplateLinterSkipSchemaValidation(false)) - if l := len(linter.Messages); l != 1 { + if !assert.Len(t, linter.Messages, 1) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 1 lint error, got %d", l) } + require.Len(t, linter.Messages, 1, "Expected 1 lint error") var depErr deprecatedAPIError require.ErrorAs(t, linter.Messages[0].Err, &depErr) @@ -267,8 +270,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { namespace, ch.Values, TemplateLinterSkipSchemaValidation(false)) - if len(linter.Messages) != 0 { - t.Errorf("expected zero messages, got %d", len(linter.Messages)) + if !assert.Empty(t, linter.Messages, "expected zero messages") { for i, msg := range linter.Messages { t.Logf("Message %d: %q", i, msg) } @@ -358,9 +360,14 @@ func TestValidateTopIndentLevel(t *testing.T) { " apiVersion:foo": true, "\n\n apiVersion:foo\n\n": true, } { - if err := validateTopIndentLevel(doc); (err == nil) == shouldFail { - t.Errorf("Expected %t for %q", shouldFail, doc) - } + t.Run(doc, func(t *testing.T) { + err := validateTopIndentLevel(doc) + if shouldFail { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) } } @@ -392,12 +399,12 @@ func TestEmptyWithCommentsManifests(t *testing.T) { namespace, values, TemplateLinterSkipSchemaValidation(false)) - if l := len(linter.Messages); l > 0 { + if !assert.Empty(t, linter.Messages) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 0 lint errors, got %d", l) } + require.Empty(t, linter.Messages, "Expected 0 lint errors") } func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index da5c3b725..4d73cb0d6 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -25,7 +25,6 @@ import ( "log" "os" "path/filepath" - "reflect" "runtime" "strings" "testing" @@ -385,11 +384,13 @@ func TestLoadInvalidArchive(t *testing.T) { {"illegal-abspath5.tgz", "/./c://foo", "chart contains illegally named files"}, {"illegal-abspath6.tgz", "\\\\?\\Some\\windows\\magic", "chart illegally contains absolute paths"}, } { - illegalChart := filepath.Join(tmpdir, tt.chartname) - writeTar(illegalChart, tt.internal, []byte("hello: world")) - _, err := Load(illegalChart) - require.Error(t, err, "expected error when unpacking illegal files") - require.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) + t.Run(tt.chartname, func(t *testing.T) { + illegalChart := filepath.Join(tmpdir, tt.chartname) + writeTar(illegalChart, tt.internal, []byte("hello: world")) + _, err := Load(illegalChart) + require.Error(t, err, "expected error when unpacking illegal files") + require.ErrorContains(t, err, tt.expectError) + }) } // Make sure that absolute path gets interpreted as relative @@ -456,7 +457,7 @@ foo: t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) require.NoError(tt, err) - assert.Truef(t, reflect.DeepEqual(values, testCase.expctedValues), "Expected values: %v, got %v", testCase.expctedValues, values) + assert.Equal(t, testCase.expctedValues, values) }) } } @@ -484,16 +485,13 @@ func TestMergeValuesV2(t *testing.T) { } testMap := MergeMaps(flatMap, nestedMap) - equal := reflect.DeepEqual(testMap, nestedMap) - assert.True(t, equal, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) + assert.Equal(t, testMap, nestedMap, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) - equal = reflect.DeepEqual(testMap, flatMap) - assert.True(t, equal, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) + assert.Equal(t, testMap, flatMap, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) - equal = reflect.DeepEqual(testMap, anotherNestedMap) - assert.True(t, equal, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) + assert.Equal(t, testMap, anotherNestedMap, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -504,8 +502,7 @@ func TestMergeValuesV2(t *testing.T) { "awesome": "stuff", }, } - equal = reflect.DeepEqual(testMap, expectedMap) - assert.True(t, equal, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) + assert.Equal(t, expectedMap, testMap, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { @@ -515,15 +512,13 @@ func verifyChart(t *testing.T, c *chart.Chart) { assert.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) numfiles := 6 - if len(c.Files) != numfiles { - t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files)) + if !assert.Len(t, c.Files, numfiles) { for _, n := range c.Files { t.Logf("\t%s", n.Name) } } - if len(c.Dependencies()) != 2 { - t.Errorf("Expected 2 dependencies, got %d (%v)", len(c.Dependencies()), c.Dependencies()) + if !assert.Len(t, c.Dependencies(), 2, "Expected 2 dependencies") { for _, d := range c.Dependencies() { t.Logf("\tSubchart: %s\n", d.Name()) } @@ -548,7 +543,7 @@ func verifyChart(t *testing.T, c *chart.Chart) { func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, @@ -563,7 +558,7 @@ func verifyDependencies(t *testing.T, c *chart.Chart) { func verifyDependenciesLock(t *testing.T, c *chart.Chart) { t.Helper() - assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 7187bdff1..92d4f024d 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -82,16 +82,15 @@ func TestResolveChartRef(t *testing.T) { } for _, tt := range tests { - _, u, err := c.ResolveChartVersion(tt.ref, tt.version) - if err != nil { - if tt.fail { - continue + t.Run(tt.name, func(t *testing.T) { + _, u, err := c.ResolveChartVersion(tt.ref, tt.version) + if err != nil { + require.True(t, tt.fail) + } else { + got := u.String() + assert.Equalf(t, tt.expect, got, "%s: expected %s, got %s", tt.name, tt.expect, got) } - t.Errorf("%s: failed with error %q", tt.name, err) - continue - } - got := u.String() - assert.Equalf(t, tt.expect, got, "%s: expected %s, got %s", tt.name, tt.expect, got) + }) } } @@ -124,35 +123,25 @@ func TestResolveChartOpts(t *testing.T) { snapshotOpts := c.Options for _, tt := range tests { - // reset chart downloader options for each test case - c.Options = snapshotOpts - - expect, err := getter.NewHTTPGetter(tt.expect...) - if err != nil { - t.Errorf("%s: failed to setup http client: %s", tt.name, err) - continue - } - - _, u, err := c.ResolveChartVersion(tt.ref, tt.version) - if err != nil { - t.Errorf("%s: failed with error %s", tt.name, err) - continue - } - - got, err := getter.NewHTTPGetter( - append( - c.Options, - getter.WithURL(u.String()), - )..., - ) - if err != nil { - t.Errorf("%s: failed to create http client: %s", tt.name, err) - continue - } - - if *(got.(*getter.HTTPGetter)) != *(expect.(*getter.HTTPGetter)) { - t.Errorf("%s: expected %s, got %s", tt.name, expect, got) - } + t.Run(tt.name, func(t *testing.T) { + // reset chart downloader options for each test case + c.Options = snapshotOpts + + expect, err := getter.NewHTTPGetter(tt.expect...) + require.NoError(t, err, "failed to setup http client") + + _, u, err := c.ResolveChartVersion(tt.ref, tt.version) + require.NoError(t, err, "failed with error") + + got, err := getter.NewHTTPGetter( + append( + c.Options, + getter.WithURL(u.String()), + )..., + ) + require.NoError(t, err, "failed to create http client") + assert.Equal(t, expect, got) + }) } } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 4d46d2692..405925a30 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -567,17 +567,16 @@ func TestUpdate(t *testing.T) { // Special handling for the rollback test case if name == "rollback after failed upgrade with removed resource" { - assert.Empty(t, result.Created, "expected 0 resource created, got %d", len(result.Created)) - assert.Len(t, result.Updated, 1, "expected 1 resource updated, got %d", len(result.Updated)) - assert.Empty(t, result.Deleted, "expected 0 resource deleted, got %d", len(result.Deleted)) + assert.Empty(t, result.Created, "expected 0 resource created") + assert.Len(t, result.Updated, 1, "expected 1 resource updated") + assert.Empty(t, result.Deleted, "expected 0 resource deleted") } else { - assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - assert.Len(t, result.Updated, 2, "expected 2 resource updated, got %d", len(result.Updated)) - assert.Len(t, result.Deleted, 1, "expected 1 resource deleted, got %d", len(result.Deleted)) + assert.Len(t, result.Created, 1, "expected 1 resource created") + assert.Len(t, result.Updated, 2, "expected 2 resource updated") + assert.Len(t, result.Deleted, 1, "expected 1 resource deleted") } if tc.ExpectedError != "" { - require.Error(t, err) require.ErrorContains(t, err, tc.ExpectedError) } else { require.NoError(t, err) @@ -702,11 +701,11 @@ func TestPerform(t *testing.T) { } err = perform(infos, fn) - assert.Equal(t, tt.err, (err != nil), "expected error: %v", tt.err) - if err != nil { - require.EqualErrorf(t, err, tt.errMessage, "expected error message: %v, got %v", tt.errMessage, err) + if tt.err { + require.EqualError(t, err, tt.errMessage) + } else { + require.NoError(t, err) } - assert.Len(t, results, tt.count, "expected %d result objects, got %d", tt.count, len(results)) }) } @@ -782,7 +781,6 @@ func TestWait(t *testing.T) { require.NoError(t, err) assert.Len(t, result.Created, 3, "expected 3 resource created, got %d", len(result.Created)) require.NoErrorf(t, c.Wait(resources, time.Second*30), "expected wait without error") - assert.GreaterOrEqualf(t, time.Since(*created), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) } diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index 6c22a732b..94e0c6050 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -16,7 +16,6 @@ limitations under the License. package strvals import ( - "bytes" "fmt" "strings" "testing" @@ -279,29 +278,21 @@ func TestParseLiteral(t *testing.T) { } for _, tt := range cases { - got, err := ParseLiteral(tt.str) - if err != nil { - if !tt.err { - require.NoError(t, err, tt.str) - } - continue - } - - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) + t.Run(tt.str, func(t *testing.T) { + got, err := ParseLiteral(tt.str) + if tt.err { + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } } @@ -386,17 +377,13 @@ func TestParseLiteralInto(t *testing.T) { } for _, tt := range tests { - if err := ParseLiteralInto(tt.input, tt.got); err != nil { - require.NoError(t, err) - } + require.NoError(t, ParseLiteralInto(tt.input, tt.got)) if tt.err { assert.Fail(t, "Expected error. Got nil", tt.input) } if tt.input2 != "" { - if err := ParseLiteralInto(tt.input2, tt.got); err != nil { - require.NoError(t, err) - } + require.NoError(t, ParseLiteralInto(tt.input2, tt.got)) if tt.err { assert.Fail(t, "Expected error. Got nil", tt.input2) } @@ -406,13 +393,9 @@ func TestParseLiteralInto(t *testing.T) { require.NoError(t, err) y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + assert.YAMLEq(t, string(y1), string(y2), tt.input) } } @@ -447,29 +430,23 @@ func TestParseLiteralNestedLevels(t *testing.T) { } for _, tt := range tests { - got, err := ParseLiteral(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := ParseLiteral(tt.str) if tt.err { + require.Error(t, err) if tt.errStr != "" { require.EqualError(t, err, tt.errStr) } - continue - } - require.NoError(t, err, tt.str) - } - - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - y2, err := yaml.Marshal(got) - require.NoError(t, err, "Error serializing parsed value") + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } } diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index e68bc4e19..c6c866711 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -16,8 +16,8 @@ limitations under the License. package strvals import ( - "bytes" "fmt" + "strconv" "strings" "testing" @@ -383,50 +383,37 @@ func TestParseSet(t *testing.T) { } for _, tt := range tests { - got, err := Parse(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := Parse(tt.str) if tt.err { - continue - } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(got) + if err != nil { + require.NoError(t, err, "Error serializing parsed value") + } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } for _, tt := range testsString { - got, err := ParseString(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := ParseString(tt.str) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2)) } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + }) } } @@ -511,33 +498,26 @@ func TestParseInto(t *testing.T) { err: false, }, } - for _, tt := range tests { - if err := ParseInto(tt.input, tt.got); err != nil { - require.NoError(t, err) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.input) - } - - if tt.input2 != "" { - if err := ParseInto(tt.input2, tt.got); err != nil { - require.NoError(t, err) - } + for i, tt := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + require.NoError(t, ParseInto(tt.input, tt.got)) if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.input2) + assert.Fail(t, "Expected error. Got nil", tt.input) } - } - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + if tt.input2 != "" { + require.NoError(t, ParseInto(tt.input2, tt.got)) + if tt.err { + assert.Fail(t, "Expected error. Got nil", tt.input2) + } + } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(tt.got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), tt.input) + }) } } @@ -564,13 +544,8 @@ func TestParseIntoString(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), input) } func TestParseJSON(t *testing.T) { @@ -650,27 +625,19 @@ func TestParseJSON(t *testing.T) { }, } for _, tt := range tests { - if err := ParseJSON(tt.input, tt.got); err != nil { + t.Run(tt.input, func(t *testing.T) { + err := ParseJSON(tt.input, tt.got) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err, "Error serializing expected value") + y2, err := yaml.Marshal(tt.got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2)) } - require.NoError(t, err, tt.input) - } - if tt.err { - require.Fail(t, "Expected error. Got nil", tt.input) - } - y1, err := yaml.Marshal(tt.expect) - if err != nil { - require.NoError(t, err, "Error serializing expected value") - } - y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + }) } } @@ -693,14 +660,10 @@ func TestParseFile(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), input) } func TestParseIntoFile(t *testing.T) { @@ -725,13 +688,9 @@ func TestParseIntoFile(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + assert.YAMLEq(t, string(y1), string(y2), input) } func TestToYAML(t *testing.T) { @@ -775,27 +734,23 @@ func TestParseSetNestedLevels(t *testing.T) { } for _, tt := range tests { - got, err := Parse(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := Parse(tt.str) if tt.err { + require.Error(t, err) if tt.errStr != "" { require.EqualError(t, err, tt.errStr) } - continue - } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } + } else { + require.NoError(t, err) - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - require.NoError(t, err, "Error serializing parsed value") + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } } From a27f3a062027d8b459eed2186076fb9384b82f38 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 18:19:56 +0200 Subject: [PATCH 129/161] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Matthieu MOREL --- pkg/cmd/rollback_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index aa60043aa..e4dbf9779 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -160,5 +160,5 @@ func TestRollbackWithLabels(t *testing.T) { updatedRel, err := releaserToV1Release(updatedReli) require.NoError(t, err) - assert.Equalf(t, updatedRel.Labels, labels1, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) +assert.Equalf(t, labels1, updatedRel.Labels, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) } From b59dfd39015311d94c04541ec5b91959c6b4b6d3 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 18:44:53 +0200 Subject: [PATCH 130/161] Update rollback_test.go Signed-off-by: Matthieu MOREL --- pkg/cmd/rollback_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index e4dbf9779..21d6a65af 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -160,5 +160,5 @@ func TestRollbackWithLabels(t *testing.T) { updatedRel, err := releaserToV1Release(updatedReli) require.NoError(t, err) -assert.Equalf(t, labels1, updatedRel.Labels, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) + assert.Equalf(t, labels1, updatedRel.Labels, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) } From bfca0688b1a44b1cf7ae37ac5f64792a8dffe7f1 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 18:45:58 +0200 Subject: [PATCH 131/161] Update show_test.go Signed-off-by: Matthieu MOREL --- pkg/cmd/show_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/show_test.go b/pkg/cmd/show_test.go index b7ad94d94..61c4f8b10 100644 --- a/pkg/cmd/show_test.go +++ b/pkg/cmd/show_test.go @@ -78,7 +78,7 @@ func TestShowPreReleaseChart(t *testing.T) { ) _, _, err := executeActionCommand(cmd) if tt.fail { - assert.ErrorContains(t, err, tt.expectedErr, "%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) + assert.ErrorContains(t, err, tt.expectedErr) } else { assert.NoError(t, err) } From 532eabf88afa2b119f90ef82d1bf309923cbbb78 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 18:47:43 +0200 Subject: [PATCH 132/161] Update chartrepo_test.go Signed-off-by: Matthieu MOREL --- pkg/repo/v1/chartrepo_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/repo/v1/chartrepo_test.go b/pkg/repo/v1/chartrepo_test.go index 54275e28d..f0e5839ac 100644 --- a/pkg/repo/v1/chartrepo_test.go +++ b/pkg/repo/v1/chartrepo_test.go @@ -175,6 +175,7 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { // versions of Darwin do not. As there are people developing Helm using both old and new versions of Darwin we test // for both messages. if runtime.GOOS == "darwin" { + require.Error(t, err) assert.True(t, strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") || strings.Contains(err.Error(), "x509: certificate signed by unknown authority"), "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) } else { assert.ErrorContainsf(t, err, "x509: certificate signed by unknown authority", "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error") From 61d99a8bdbc90219c474c96e11790ab6a90cde61 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 18:53:45 +0200 Subject: [PATCH 133/161] Update labels_test.go Signed-off-by: Matthieu MOREL --- pkg/storage/driver/labels_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index 481b8c467..34f01be79 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -45,7 +45,11 @@ func TestLabelsMatch(t *testing.T) { for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - require.False(t, !tt.set1.match(tt.set2) && tt.expect) + if tt.expect { + require.True(t, tt.set1.match(tt.set2)) + } else { + require.False(t, tt.set1.match(tt.set2)) + } }) } } From 622f16b37fdb1f1915aece9436165dc53c26b3c5 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 24 Jul 2026 19:06:05 +0200 Subject: [PATCH 134/161] Update resource_test.go Signed-off-by: Matthieu MOREL --- pkg/kube/resource_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/kube/resource_test.go b/pkg/kube/resource_test.go index 18501d4e8..8bc644833 100644 --- a/pkg/kube/resource_test.go +++ b/pkg/kube/resource_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/resource" @@ -41,11 +42,11 @@ func TestResourceList(t *testing.T) { assert.Equal(t, "pod", r1.Get(info("bar")).Mapping.Resource.Resource, "expected get pod") diff := r1.Difference(r2) - assert.Len(t, diff, 1, "expected 1 result") + require.Len(t, diff, 1, "expected 1 result") assert.Contains(t, diff, info("foo"), "expected diff to return foo") inter := r1.Intersect(r2) - assert.Len(t, inter, 1, "expected 1 result") + require.Len(t, inter, 1, "expected 1 result") assert.Contains(t, inter, info("bar"), "expected intersect to return bar") } From f8180e6de473bb4b1008b76aa2ac63b8bcd104c0 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Wed, 26 Nov 2025 18:06:31 +0100 Subject: [PATCH 135/161] feat(rollback): add --description flag to provide rollback reason Add a new --description flag to the helm rollback command that allows users to specify a custom description explaining why the rollback was performed. This description is stored in the release metadata. Changes: - Add Description field to the Rollback action struct - Add --description flag to the rollback CLI command - Add 512 character limit validation for the description - Default to 'Rollback to ' when no description is provided The description flag is optional and follows the same pattern used by the install and upgrade commands. Closes #XXXX Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 10 +- pkg/action/rollback_test.go | 135 +++++++++++++++++- pkg/cmd/rollback.go | 9 ++ pkg/cmd/rollback_test.go | 84 +++++++++++ .../output/rollback-with-description.txt | 2 + 5 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 pkg/cmd/testdata/output/rollback-with-description.txt diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 6fc449c30..a4eb09643 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -59,6 +59,8 @@ type Rollback struct { ServerSideApply string CleanupOnFail bool MaxHistory int // MaxHistory limits the maximum number of revisions saved per release + // Description is the description of this rollback operation + Description string } // NewRollback creates a new Rollback object with the given configuration. @@ -169,6 +171,12 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele return nil, nil, false, err } + // Determine the description for this rollback + description := fmt.Sprintf("Rollback to %d", previousVersion) + if r.Description != "" { + description = r.Description + } + // Store a new release object with previous release's configuration targetRelease := &release.Release{ Name: name, @@ -183,7 +191,7 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele RollbackRevision: previousVersion, // Because we lose the reference to previous version elsewhere, we set the // message here, and only override it later if we experience failure. - Description: fmt.Sprintf("Rollback to %d", previousVersion), + Description: description, }, Version: currentRelease.Version + 1, Labels: previousRelease.Labels, diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index 7ffd90d25..f85d1a690 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -27,14 +27,26 @@ import ( "helm.sh/helm/v4/pkg/kube" kubefake "helm.sh/helm/v4/pkg/kube/fake" + "helm.sh/helm/v4/pkg/release/common" ) +func rollbackAction(t *testing.T) *Rollback { + t.Helper() + config := actionConfigFixture(t) + rollAction := NewRollback(config) + return rollAction +} + func TestNewRollback(t *testing.T) { + is := assert.New(t) config := actionConfigFixture(t) - client := NewRollback(config) - assert.NotNil(t, client) - assert.Equal(t, config, client.cfg) + rollback := NewRollback(config) + + is.NotNil(rollback) + is.Equal(config, rollback.cfg) + is.Equal(DryRunNone, rollback.DryRunStrategy) + is.Empty(rollback.Description) } func TestRollbackRun_UnreachableKubeClient(t *testing.T) { @@ -131,3 +143,120 @@ func TestRollbackRevisionZeroForNonRollback(t *testing.T) { assert.Equal(t, 0, r.Info.RollbackRevision) } + +func TestRollback_WithDescription(t *testing.T) { + is := assert.New(t) + req := require.New(t) + + rollAction := rollbackAction(t) + + // Create two releases - version 1 (superseded) and version 2 (deployed) + rel1 := releaseStub() + rel1.Name = "test-release" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + // Set custom description + customDescription := "Rollback due to critical bug in version 2" + rollAction.Description = customDescription + rollAction.Version = 1 + rollAction.ServerSideApply = "false" // Disable server-side apply for testing + + err := rollAction.Run("test-release") + req.NoError(err) + + // Get the new release (version 3) + newReleasei, err := rollAction.cfg.Releases.Get("test-release", 3) + req.NoError(err) + newRelease, err := releaserToV1Release(newReleasei) + req.NoError(err) + + // Verify the custom description was set + is.Equal(customDescription, newRelease.Info.Description) +} + +func TestRollback_DefaultDescription(t *testing.T) { + is := assert.New(t) + req := require.New(t) + + rollAction := rollbackAction(t) + + // Create two releases - version 1 (superseded) and version 2 (deployed) + rel1 := releaseStub() + rel1.Name = "test-release-default" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release-default" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + // Don't set a description, rely on default + rollAction.Version = 1 + rollAction.ServerSideApply = "false" // Disable server-side apply for testing + + err := rollAction.Run("test-release-default") + req.NoError(err) + + // Get the new release (version 3) + newReleasei, err := rollAction.cfg.Releases.Get("test-release-default", 3) + req.NoError(err) + newRelease, err := releaserToV1Release(newReleasei) + req.NoError(err) + + // Verify the default description was set + is.Equal("Rollback to 1", newRelease.Info.Description) +} + +func TestRollback_EmptyDescription(t *testing.T) { + is := assert.New(t) + req := require.New(t) + + rollAction := rollbackAction(t) + + // Create two releases - version 1 (superseded) and version 2 (deployed) + rel1 := releaseStub() + rel1.Name = "test-release-empty" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release-empty" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" // client-side apply + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + // Set empty description (should use default) + rollAction.Description = "" + rollAction.Version = 1 + rollAction.ServerSideApply = "false" // Disable server-side apply for testing + + err := rollAction.Run("test-release-empty") + req.NoError(err) + + // Get the new release (version 3) + newReleasei, err := rollAction.cfg.Releases.Get("test-release-empty", 3) + req.NoError(err) + newRelease, err := releaserToV1Release(newReleasei) + req.NoError(err) + + // Verify the default description was used for empty string + is.Equal("Rollback to 1", newRelease.Info.Description) +} diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index b716dae10..fb2b80c5c 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -38,6 +38,9 @@ second is a revision (version) number. If this argument is omitted or set to To see revision numbers, run 'helm history RELEASE'. ` +// maxDescriptionLength is the maximum length allowed for a rollback description +const maxDescriptionLength = 512 + func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewRollback(cfg) client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) @@ -67,6 +70,11 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client.Version = ver } + // Validate description length + if len(client.Description) > maxDescriptionLength { + return fmt.Errorf("description must be %d characters or less, got %d", maxDescriptionLength, len(client.Description)) + } + dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, false) if err != nil { return err @@ -83,6 +91,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } f := cmd.Flags() + f.StringVar(&client.Description, "description", "", fmt.Sprintf("add a custom description for the rollback (max %d characters)", maxDescriptionLength)) f.BoolVar(&client.ForceReplace, "force-replace", false, "force resource updates by replacement") f.BoolVar(&client.ForceReplace, "force", false, "deprecated") f.MarkDeprecated("force", "use --force-replace instead") diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 21d6a65af..f607f57b1 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -18,6 +18,7 @@ package cmd import ( "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -81,6 +82,11 @@ func TestRollbackCmd(t *testing.T) { golden: "output/rollback-no-args.txt", rels: rels, wantError: true, + }, { + name: "rollback a release with description", + cmd: "rollback funny-honey 1 --description 'Reverting due to bug in version 2'", + golden: "output/rollback-with-description.txt", + rels: rels, }} runTestCmd(t, tests) } @@ -127,6 +133,84 @@ func TestRollbackFileCompletion(t *testing.T) { checkFileCompletion(t, "rollback myrelease 1", false) } +func TestRollbackWithDescription(t *testing.T) { + releaseName := "funny-bunny-desc" + rels := []*release.Release{ + { + Name: releaseName, + Info: &release.Info{Status: common.StatusSuperseded}, + Chart: &chart.Chart{}, + Version: 1, + }, + { + Name: releaseName, + Info: &release.Info{Status: common.StatusDeployed}, + Chart: &chart.Chart{}, + Version: 2, + }, + } + storage := storageFixture() + for _, rel := range rels { + if err := storage.Create(rel); err != nil { + t.Fatal(err) + } + } + + customDescription := "Rollback due to critical bug in version 2" + _, _, err := executeActionCommandC(storage, fmt.Sprintf("rollback %s 1 --description '%s'", releaseName, customDescription)) + if err != nil { + t.Fatalf("unexpected error, got '%v'", err) + } + + // Verify the description was stored correctly + updatedReli, err := storage.Get(releaseName, 3) + if err != nil { + t.Fatalf("unexpected error getting release, got '%v'", err) + } + updatedRel, err := releaserToV1Release(updatedReli) + if err != nil { + t.Fatalf("unexpected error converting release, got '%v'", err) + } + + if updatedRel.Info.Description != customDescription { + t.Errorf("Expected description '%s', got '%s'", customDescription, updatedRel.Info.Description) + } +} + +func TestRollbackDescriptionTooLong(t *testing.T) { + releaseName := "funny-bunny-long-desc" + rels := []*release.Release{ + { + Name: releaseName, + Info: &release.Info{Status: common.StatusSuperseded}, + Chart: &chart.Chart{}, + Version: 1, + }, + { + Name: releaseName, + Info: &release.Info{Status: common.StatusDeployed}, + Chart: &chart.Chart{}, + Version: 2, + }, + } + storage := storageFixture() + for _, rel := range rels { + if err := storage.Create(rel); err != nil { + t.Fatal(err) + } + } + + // Create a description that exceeds the 512 character limit + longDescription := strings.Repeat("a", 513) + _, _, err := executeActionCommandC(storage, fmt.Sprintf("rollback %s 1 --description '%s'", releaseName, longDescription)) + if err == nil { + t.Error("expected error for description exceeding max length, got success") + } + if err != nil && !strings.Contains(err.Error(), "description must be 512 characters or less") { + t.Errorf("expected error about description length, got: %v", err) + } +} + func TestRollbackWithLabels(t *testing.T) { labels1 := map[string]string{"operation": "install", "firstLabel": "firstValue"} labels2 := map[string]string{"operation": "upgrade", "secondLabel": "secondValue"} diff --git a/pkg/cmd/testdata/output/rollback-with-description.txt b/pkg/cmd/testdata/output/rollback-with-description.txt new file mode 100644 index 000000000..a034dd2df --- /dev/null +++ b/pkg/cmd/testdata/output/rollback-with-description.txt @@ -0,0 +1,2 @@ +Rollback was a success! Happy Helming! + From b606955f095408270914c47eac8414b9061bfb49 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 16 Feb 2026 13:50:56 +0100 Subject: [PATCH 136/161] Set 256 as limit for maxDescriptionLength. 256 comes from MAX value for key and value Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index fb2b80c5c..35257a779 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -39,7 +39,7 @@ To see revision numbers, run 'helm history RELEASE'. ` // maxDescriptionLength is the maximum length allowed for a rollback description -const maxDescriptionLength = 512 +const maxDescriptionLength = 256 func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewRollback(cfg) From e69e424ab1917f0d53eafe63c408b5280b39624a Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:17:34 +0100 Subject: [PATCH 137/161] Changed if construction Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index a4eb09643..5f4c5a8a9 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -172,9 +172,9 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele } // Determine the description for this rollback - description := fmt.Sprintf("Rollback to %d", previousVersion) - if r.Description != "" { - description = r.Description + description := r.Description + if description == "" { + description = fmt.Sprintf("Rollback to %d", previousVersion) } // Store a new release object with previous release's configuration From cb91040c447723a7338a513a6d1604e5daaa1e0b Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 23 Feb 2026 08:40:44 +0100 Subject: [PATCH 138/161] Enhanced rollback description length Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 6 ++++ pkg/action/rollback_test.go | 64 +++++++++++++++++++++++++++++++++++++ pkg/cmd/rollback.go | 9 ++---- pkg/cmd/rollback_test.go | 5 ++- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 5f4c5a8a9..93a7ab194 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -31,6 +31,8 @@ import ( "helm.sh/helm/v4/pkg/storage/driver" ) +const MaxDescriptionLength = 256 + // Rollback is the action for rolling back to a given release. // // It provides the implementation of 'helm rollback'. @@ -118,6 +120,10 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele return nil, nil, false, errInvalidRevision } + if len(r.Description) > MaxDescriptionLength { + return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, len(r.Description)) + } + currentReleasei, err := r.cfg.Releases.Last(name) if err != nil { return nil, nil, false, err diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index f85d1a690..1d483a17e 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -20,6 +20,7 @@ import ( "context" "errors" "io" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -260,3 +261,66 @@ func TestRollback_EmptyDescription(t *testing.T) { // Verify the default description was used for empty string is.Equal("Rollback to 1", newRelease.Info.Description) } + +func TestRollback_DescriptionTooLong(t *testing.T) { + req := require.New(t) + + rollAction := rollbackAction(t) + + rel1 := releaseStub() + rel1.Name = "test-release-desc-long" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release-desc-long" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + rollAction.Description = strings.Repeat("a", MaxDescriptionLength+1) + rollAction.Version = 1 + rollAction.ServerSideApply = "false" + + err := rollAction.Run("test-release-desc-long") + req.Error(err) + req.Contains(err.Error(), "description must be") +} + +func TestRollback_DescriptionAtMaxLength(t *testing.T) { + is := assert.New(t) + req := require.New(t) + + rollAction := rollbackAction(t) + + rel1 := releaseStub() + rel1.Name = "test-release-desc-max" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release-desc-max" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + rollAction.Description = strings.Repeat("a", MaxDescriptionLength) + rollAction.Version = 1 + rollAction.ServerSideApply = "false" + + err := rollAction.Run("test-release-desc-max") + req.NoError(err) + + newReleasei, err := rollAction.cfg.Releases.Get("test-release-desc-max", 3) + req.NoError(err) + newRelease, err := releaserToV1Release(newReleasei) + req.NoError(err) + + is.Equal(strings.Repeat("a", MaxDescriptionLength), newRelease.Info.Description) +} diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 35257a779..1fbd04fc8 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -38,9 +38,6 @@ second is a revision (version) number. If this argument is omitted or set to To see revision numbers, run 'helm history RELEASE'. ` -// maxDescriptionLength is the maximum length allowed for a rollback description -const maxDescriptionLength = 256 - func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewRollback(cfg) client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) @@ -71,8 +68,8 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } // Validate description length - if len(client.Description) > maxDescriptionLength { - return fmt.Errorf("description must be %d characters or less, got %d", maxDescriptionLength, len(client.Description)) + if len(client.Description) > action.MaxDescriptionLength { + return fmt.Errorf("description must be %d characters or less, got %d", action.MaxDescriptionLength, len(client.Description)) } dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, false) @@ -91,7 +88,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } f := cmd.Flags() - f.StringVar(&client.Description, "description", "", fmt.Sprintf("add a custom description for the rollback (max %d characters)", maxDescriptionLength)) + f.StringVar(&client.Description, "description", "", fmt.Sprintf("add a custom description for the rollback (max %d characters)", action.MaxDescriptionLength)) f.BoolVar(&client.ForceReplace, "force-replace", false, "force resource updates by replacement") f.BoolVar(&client.ForceReplace, "force", false, "deprecated") f.MarkDeprecated("force", "use --force-replace instead") diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index f607f57b1..44119d9e7 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -200,13 +200,12 @@ func TestRollbackDescriptionTooLong(t *testing.T) { } } - // Create a description that exceeds the 512 character limit - longDescription := strings.Repeat("a", 513) + longDescription := strings.Repeat("a", action.MaxDescriptionLength+1) _, _, err := executeActionCommandC(storage, fmt.Sprintf("rollback %s 1 --description '%s'", releaseName, longDescription)) if err == nil { t.Error("expected error for description exceeding max length, got success") } - if err != nil && !strings.Contains(err.Error(), "description must be 512 characters or less") { + if err != nil && !strings.Contains(err.Error(), fmt.Sprintf("description must be %d characters or less", action.MaxDescriptionLength)) { t.Errorf("expected error about description length, got: %v", err) } } From 8a34f3b7b4d9ffa4e82c7893eb3d8572fd464198 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 23 Feb 2026 08:45:48 +0100 Subject: [PATCH 139/161] Use rune count to count properly multi-byte UTF-8 characters Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 5 +++-- pkg/action/rollback_test.go | 36 ++++++++++++++++++++++++++++++++++++ pkg/cmd/rollback.go | 5 +++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 93a7ab194..497842c3c 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "time" + "unicode/utf8" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -120,8 +121,8 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele return nil, nil, false, errInvalidRevision } - if len(r.Description) > MaxDescriptionLength { - return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, len(r.Description)) + if utf8.RuneCountInString(r.Description) > MaxDescriptionLength { + return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, utf8.RuneCountInString(r.Description)) } currentReleasei, err := r.cfg.Releases.Last(name) diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index 1d483a17e..af7fe6107 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -324,3 +324,39 @@ func TestRollback_DescriptionAtMaxLength(t *testing.T) { is.Equal(strings.Repeat("a", MaxDescriptionLength), newRelease.Info.Description) } + +func TestRollback_DescriptionMultiByteCharacters(t *testing.T) { + is := assert.New(t) + req := require.New(t) + + rollAction := rollbackAction(t) + + rel1 := releaseStub() + rel1.Name = "test-release-desc-utf8" + rel1.Version = 1 + rel1.Info.Status = common.StatusSuperseded + rel1.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel1)) + + rel2 := releaseStub() + rel2.Name = "test-release-desc-utf8" + rel2.Version = 2 + rel2.Info.Status = common.StatusDeployed + rel2.ApplyMethod = "csa" + req.NoError(rollAction.cfg.Releases.Create(rel2)) + + // "Ê" is 2 bytes in UTF-8 but 1 rune + rollAction.Description = strings.Repeat("Ê", MaxDescriptionLength) + rollAction.Version = 1 + rollAction.ServerSideApply = "false" + + err := rollAction.Run("test-release-desc-utf8") + req.NoError(err) + + newReleasei, err := rollAction.cfg.Releases.Get("test-release-desc-utf8", 3) + req.NoError(err) + newRelease, err := releaserToV1Release(newReleasei) + req.NoError(err) + + is.Equal(strings.Repeat("Ê", MaxDescriptionLength), newRelease.Info.Description) +} diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 1fbd04fc8..bad1e3068 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -21,6 +21,7 @@ import ( "io" "strconv" "time" + "unicode/utf8" "github.com/spf13/cobra" @@ -68,8 +69,8 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } // Validate description length - if len(client.Description) > action.MaxDescriptionLength { - return fmt.Errorf("description must be %d characters or less, got %d", action.MaxDescriptionLength, len(client.Description)) + if utf8.RuneCountInString(client.Description) > action.MaxDescriptionLength { + return fmt.Errorf("description must be %d characters or less, got %d", action.MaxDescriptionLength, utf8.RuneCountInString(client.Description)) } dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, false) From a92611c20241be8e7dc32f9b229afd2a722a06f8 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:07:13 +0100 Subject: [PATCH 140/161] Enhance rune count in pkg/cmd/rollback.go and pkg/action/rollback.go Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 4 ++-- pkg/cmd/rollback.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 497842c3c..9a5526e94 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -121,8 +121,8 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele return nil, nil, false, errInvalidRevision } - if utf8.RuneCountInString(r.Description) > MaxDescriptionLength { - return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, utf8.RuneCountInString(r.Description)) + if descLen := utf8.RuneCountInString(r.Description); descLen > MaxDescriptionLength { + return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, descLen) } currentReleasei, err := r.cfg.Releases.Last(name) diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index bad1e3068..62d0be4af 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -69,8 +69,8 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } // Validate description length - if utf8.RuneCountInString(client.Description) > action.MaxDescriptionLength { - return fmt.Errorf("description must be %d characters or less, got %d", action.MaxDescriptionLength, utf8.RuneCountInString(client.Description)) + if descLen := utf8.RuneCountInString(client.Description); descLen > action.MaxDescriptionLength { + return fmt.Errorf("description must be %d characters or less, got %d", action.MaxDescriptionLength, descLen) } dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, false) From b177a8e9060720e91c402cdba2224c6d58789fa3 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:45:01 +0100 Subject: [PATCH 141/161] Removed extra space in rollback-with-description.txt Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/testdata/output/rollback-with-description.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/cmd/testdata/output/rollback-with-description.txt b/pkg/cmd/testdata/output/rollback-with-description.txt index a034dd2df..ae3c6f1c4 100644 --- a/pkg/cmd/testdata/output/rollback-with-description.txt +++ b/pkg/cmd/testdata/output/rollback-with-description.txt @@ -1,2 +1 @@ Rollback was a success! Happy Helming! - From e73dfab5fb47c9f3a0f24cb3f3a7a4aa8b65143e Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:29:30 +0100 Subject: [PATCH 142/161] refactor(test): reuse existing rollback.txt golden file Remove duplicate rollback-with-description.txt fixture that had identical content to rollback.txt. Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback_test.go | 2 +- pkg/cmd/testdata/output/rollback-with-description.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 pkg/cmd/testdata/output/rollback-with-description.txt diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 44119d9e7..2e523a5f6 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -85,7 +85,7 @@ func TestRollbackCmd(t *testing.T) { }, { name: "rollback a release with description", cmd: "rollback funny-honey 1 --description 'Reverting due to bug in version 2'", - golden: "output/rollback-with-description.txt", + golden: "output/rollback.txt", rels: rels, }} runTestCmd(t, tests) diff --git a/pkg/cmd/testdata/output/rollback-with-description.txt b/pkg/cmd/testdata/output/rollback-with-description.txt deleted file mode 100644 index ae3c6f1c4..000000000 --- a/pkg/cmd/testdata/output/rollback-with-description.txt +++ /dev/null @@ -1 +0,0 @@ -Rollback was a success! Happy Helming! From 91520a78063582ab8265d9364815665f688deebc Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:32:41 +0100 Subject: [PATCH 143/161] refactor(rollback): validate description length before cluster reachability check Move description length validation to the beginning of Run(), before IsReachable(), so programmatic callers get an immediate validation error instead of a potentially misleading cluster reachability failure. Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 9a5526e94..52fdfbbf8 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -77,6 +77,10 @@ func NewRollback(cfg *Configuration) *Rollback { // Run executes 'helm rollback' against the given release. func (r *Rollback) Run(name string) error { + if descLen := utf8.RuneCountInString(r.Description); descLen > MaxDescriptionLength { + return fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, descLen) + } + if err := r.cfg.KubeClient.IsReachable(); err != nil { return err } @@ -121,10 +125,6 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele return nil, nil, false, errInvalidRevision } - if descLen := utf8.RuneCountInString(r.Description); descLen > MaxDescriptionLength { - return nil, nil, false, fmt.Errorf("description must be %d characters or less, got %d", MaxDescriptionLength, descLen) - } - currentReleasei, err := r.cfg.Releases.Last(name) if err != nil { return nil, nil, false, err From 4fcc4e4b3db363654f3dd5240211b195e309970e Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 22 Jun 2026 08:25:49 +0200 Subject: [PATCH 144/161] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/action/rollback.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 52fdfbbf8..b24b4a83d 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -32,6 +32,8 @@ import ( "helm.sh/helm/v4/pkg/storage/driver" ) +// MaxDescriptionLength is the maximum length allowed for a rollback description, +// including values provided via the --description flag and Rollback.Description. const MaxDescriptionLength = 256 // Rollback is the action for rolling back to a given release. From f1ede7c9c114c745da2f5c6cef8d27e1eb342498 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:58:37 +0200 Subject: [PATCH 145/161] Potential fix for pull request finding If the CLI-side description validation is removed, the unicode/utf8 import becomes unused and should also be dropped. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 62d0be4af..12f4b6b3c 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -21,7 +21,6 @@ import ( "io" "strconv" "time" - "unicode/utf8" "github.com/spf13/cobra" From 500f02d597628d8ca7be8b530edcbedbf397b676 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:22:55 +0200 Subject: [PATCH 146/161] Readded "unicode/utf8" Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 12f4b6b3c..62d0be4af 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -21,6 +21,7 @@ import ( "io" "strconv" "time" + "unicode/utf8" "github.com/spf13/cobra" From 94a3315f4d699c6bb4140550d4c98b46bb4382d2 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:41:29 +0200 Subject: [PATCH 147/161] Added missing import Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 2e523a5f6..00b314a4e 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/action" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" From f3edb83df48c505878ffd3ebb89ef6a809e14008 Mon Sep 17 00:00:00 2001 From: MrJack <36191829+biagiopietro@users.noreply.github.com> Date: Mon, 27 Jul 2026 14:46:55 +0200 Subject: [PATCH 148/161] Make golangci-lint happy Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com> --- pkg/cmd/rollback_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 00b314a4e..1a617b228 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -23,8 +23,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "helm.sh/helm/v4/pkg/action" + "helm.sh/helm/v4/pkg/action" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" From bbaf420a101379dad4f8452129cf26f2fff7e536 Mon Sep 17 00:00:00 2001 From: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:42:43 -0500 Subject: [PATCH 149/161] fix(scripts): address cache-busting review feedback Signed-off-by: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> --- scripts/get-helm-3 | 4 ++-- scripts/get-helm-4 | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index dad66ab20..117ae3e03 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -114,8 +114,8 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL - # Append a cache-busting query string to avoid CDN edge servers - # serving stale version files after a new release. + # The current CDN does not revalidate on the request no-cache directive, + # so use a unique query while retaining no-cache for compliant intermediaries. local latest_release_url="https://get.helm.sh/helm3-latest-version?ts=$(date +%s)" local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then diff --git a/scripts/get-helm-4 b/scripts/get-helm-4 index 1c90bbad5..0ff312a7f 100644 --- a/scripts/get-helm-4 +++ b/scripts/get-helm-4 @@ -114,12 +114,14 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL - local latest_release_url="https://get.helm.sh/helm4-latest-version" + # The current CDN does not revalidate on the request no-cache directive, + # so use a unique query while retaining no-cache for compliant intermediaries. + local latest_release_url="https://get.helm.sh/helm4-latest-version?ts=$(date +%s)" local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then - latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true ) + latest_release_response=$( curl -L --silent --show-error --fail -H "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) elif [ "${HAS_WGET}" == "true" ]; then - latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true ) + latest_release_response=$( wget "$latest_release_url" --header="Cache-Control: no-cache" -q -O - 2>&1 || true ) fi TAG=$( echo "$latest_release_response" | grep '^v[0-9]' ) if [ "x$TAG" == "x" ]; then From 24bbb46c62a54000394ce77c4e3fda17d5566ffc Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 27 Jul 2026 19:53:24 +0200 Subject: [PATCH 150/161] chore: fix gofumpt issues Signed-off-by: Matthieu MOREL --- .golangci.yml | 5 + internal/chart/v3/lint/lint_test.go | 18 ++- .../chart/v3/lint/rules/chartfile_test.go | 22 +-- internal/chart/v3/lint/rules/template_test.go | 17 +- .../chart/v3/lint/support/message_test.go | 2 +- internal/monocular/client.go | 1 - .../plugin/installer/http_installer_test.go | 4 +- .../plugin/installer/vcs_installer_test.go | 1 + internal/plugin/loader.go | 1 - internal/plugin/metadata.go | 3 +- internal/plugin/verify_test.go | 6 +- internal/release/v2/release.go | 6 +- .../release/v2/util/manifest_sorter_test.go | 15 +- internal/third_party/dep/fs/fs_test.go | 12 +- internal/tlsutil/tls.go | 3 +- pkg/action/get_metadata_test.go | 2 +- pkg/action/hooks.go | 12 +- pkg/action/hooks_test.go | 10 +- pkg/action/install.go | 1 - pkg/action/install_test.go | 4 + pkg/action/list.go | 3 +- pkg/action/release_testing.go | 1 - pkg/action/rollback.go | 1 - pkg/action/uninstall.go | 1 - pkg/action/uninstall_test.go | 1 + pkg/chart/common.go | 8 +- pkg/chart/common/capabilities.go | 1 - pkg/chart/v2/lint/lint_test.go | 18 ++- pkg/chart/v2/lint/rules/chartfile.go | 1 - pkg/chart/v2/lint/rules/chartfile_test.go | 26 +-- pkg/chart/v2/lint/rules/template_test.go | 11 +- pkg/chart/v2/lint/support/message_test.go | 2 +- pkg/chart/v2/loader/load_test.go | 3 +- pkg/cmd/completion.go | 1 + pkg/cmd/dependency_build_test.go | 3 - pkg/cmd/dependency_test.go | 12 +- pkg/cmd/dependency_update_test.go | 1 - pkg/cmd/flags.go | 1 - pkg/cmd/get_hooks.go | 1 - pkg/cmd/get_manifest.go | 1 - pkg/cmd/get_metadata.go | 1 - pkg/cmd/get_notes.go | 1 - pkg/cmd/get_values.go | 1 - pkg/cmd/load_plugins.go | 1 - pkg/cmd/pull.go | 1 - pkg/cmd/pull_test.go | 3 +- pkg/cmd/push.go | 1 - pkg/cmd/repo_remove_test.go | 4 +- pkg/cmd/repo_update_test.go | 2 +- pkg/cmd/root.go | 3 - pkg/cmd/search_hub_test.go | 10 +- pkg/cmd/search_repo_test.go | 3 +- pkg/cmd/show.go | 1 - pkg/cmd/status_test.go | 3 +- pkg/cmd/template.go | 1 - pkg/engine/engine.go | 8 +- pkg/engine/engine_test.go | 1 + pkg/engine/funcs.go | 1 - pkg/engine/funcs_test.go | 152 +++++++++--------- pkg/getter/ocigetter.go | 1 - pkg/getter/plugingetter.go | 1 - pkg/getter/plugingetter_test.go | 1 - pkg/kube/client.go | 6 +- pkg/kube/client_test.go | 3 +- pkg/kube/converter.go | 8 +- pkg/provenance/sign.go | 1 - pkg/registry/client.go | 4 +- pkg/registry/client_scope_test.go | 1 + pkg/release/common.go | 4 +- pkg/release/v1/release.go | 6 +- pkg/release/v1/util/manifest_sorter_test.go | 15 +- pkg/repo/v1/index_test.go | 2 +- pkg/repo/v1/repo_test.go | 10 +- pkg/storage/driver/labels_test.go | 2 +- pkg/storage/driver/memory_test.go | 10 +- pkg/storage/driver/records_test.go | 12 +- pkg/storage/driver/sql.go | 21 +-- pkg/storage/driver/util_test.go | 4 +- pkg/storage/storage_test.go | 9 +- pkg/strvals/literal_parser_test.go | 3 +- pkg/strvals/parser_test.go | 3 +- 81 files changed, 307 insertions(+), 260 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5b6d7cf8e..9daa85ad5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,7 @@ formatters: enable: - gofmt + - gofumpt - goimports exclusions: @@ -10,6 +11,10 @@ formatters: gofmt: simplify: true + gofumpt: + module-path: helm.sh/helm/v4 + extra-rules: false + goimports: local-prefixes: - helm.sh/helm/v4 diff --git a/internal/chart/v3/lint/lint_test.go b/internal/chart/v3/lint/lint_test.go index b0a7ce651..5eb185f07 100644 --- a/internal/chart/v3/lint/lint_test.go +++ b/internal/chart/v3/lint/lint_test.go @@ -30,14 +30,16 @@ import ( const namespace = "testNamespace" -const badChartDir = "rules/testdata/badchartfile" -const badValuesFileDir = "rules/testdata/badvaluesfile" -const badYamlFileDir = "rules/testdata/albatross" -const badCrdFileDir = "rules/testdata/badcrdfile" -const goodChartDir = "rules/testdata/goodone" -const subChartValuesDir = "rules/testdata/withsubchart" -const malformedTemplate = "rules/testdata/malformed-template" -const invalidChartFileDir = "rules/testdata/invalidchartfile" +const ( + badChartDir = "rules/testdata/badchartfile" + badValuesFileDir = "rules/testdata/badvaluesfile" + badYamlFileDir = "rules/testdata/albatross" + badCrdFileDir = "rules/testdata/badcrdfile" + goodChartDir = "rules/testdata/goodone" + subChartValuesDir = "rules/testdata/withsubchart" + malformedTemplate = "rules/testdata/malformed-template" + invalidChartFileDir = "rules/testdata/invalidchartfile" +) func TestBadChartV3(t *testing.T) { var values map[string]any diff --git a/internal/chart/v3/lint/rules/chartfile_test.go b/internal/chart/v3/lint/rules/chartfile_test.go index 0638589b6..e06d7bdc4 100644 --- a/internal/chart/v3/lint/rules/chartfile_test.go +++ b/internal/chart/v3/lint/rules/chartfile_test.go @@ -44,8 +44,10 @@ var ( nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml") ) -var badChart, _ = chartutil.LoadChartfile(badChartFilePath) -var badChartName, _ = chartutil.LoadChartfile(badChartNamePath) +var ( + badChart, _ = chartutil.LoadChartfile(badChartFilePath) + badChartName, _ = chartutil.LoadChartfile(badChartNamePath) +) // Validation functions Test func TestValidateChartYamlNotDirectory(t *testing.T) { @@ -68,7 +70,7 @@ func TestValidateChartName(t *testing.T) { } func TestValidateChartVersion(t *testing.T) { - var failTest = []struct { + failTest := []struct { Version string ErrorMsg string }{ @@ -80,7 +82,7 @@ func TestValidateChartVersion(t *testing.T) { {"1", "'1' is not a valid SemVerV2"}, } - var successTest = []string{"0.0.1", "0.0.1+build", "0.0.1-beta"} + successTest := []string{"0.0.1", "0.0.1+build", "0.0.1-beta"} for i, test := range failTest { t.Run(strconv.Itoa(i), func(t *testing.T) { @@ -96,7 +98,7 @@ func TestValidateChartVersion(t *testing.T) { } func TestValidateChartMaintainer(t *testing.T) { - var failTest = []struct { + failTest := []struct { Name string Email string ErrorMsg string @@ -106,7 +108,7 @@ func TestValidateChartMaintainer(t *testing.T) { {"John Snow", "wrongFormatEmail.com", "invalid email"}, } - var successTest = []struct { + successTest := []struct { Name string Email string }{ @@ -134,8 +136,8 @@ func TestValidateChartMaintainer(t *testing.T) { } func TestValidateChartSources(t *testing.T) { - var failTest = []string{"", "RiverRun", "john@winterfell", "riverrun.io"} - var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} + failTest := []string{"", "RiverRun", "john@winterfell", "riverrun.io"} + successTest := []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Sources = []string{test} @@ -166,8 +168,8 @@ func TestValidateChartIconPresence(t *testing.T) { } func TestValidateChartIconURL(t *testing.T) { - var failTest = []string{"RiverRun", "john@winterfell", "riverrun.io"} - var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} + failTest := []string{"RiverRun", "john@winterfell", "riverrun.io"} + successTest := []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Icon = test diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index 3271a5bbe..4a1e15f55 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -35,11 +35,11 @@ import ( const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { - var failTest = []string{"/foo", "/test.toml"} + failTest := []string{"/foo", "/test.toml"} for _, test := range failTest { require.ErrorContains(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } - var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} + successTest := []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } @@ -47,8 +47,10 @@ func TestValidateAllowedExtension(t *testing.T) { var values = map[string]any{"nameOverride": "", "httpPort": 80} -const namespace = "testNamespace" -const strict = false +const ( + namespace = "testNamespace" + strict = false +) func TestTemplateParsing(t *testing.T) { linter := support.Linter{ChartDir: templateTestBasedir} @@ -59,8 +61,10 @@ func TestTemplateParsing(t *testing.T) { assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } -var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") -var ignoredTemplatePath = filepath.Join(templateTestBasedir, "fail.yaml.ignored") +var ( + wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") + ignoredTemplatePath = filepath.Join(templateTestBasedir, "fail.yaml.ignored") +) // Test a template with all the existing features: // namespaces, partial templates @@ -382,6 +386,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } require.Empty(t, linter.Messages, "Expected 0 lint errors") } + func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ APIVersion: "v1", diff --git a/internal/chart/v3/lint/support/message_test.go b/internal/chart/v3/lint/support/message_test.go index d07cf9ed4..6edd9261f 100644 --- a/internal/chart/v3/lint/support/message_test.go +++ b/internal/chart/v3/lint/support/message_test.go @@ -27,7 +27,7 @@ import ( var errLint = errors.New("lint failed") func TestRunLinterRule(t *testing.T) { - var tests = []struct { + tests := []struct { Severity int LintError error ExpectedMessages int diff --git a/internal/monocular/client.go b/internal/monocular/client.go index cd1a0d666..a6e6be0d4 100644 --- a/internal/monocular/client.go +++ b/internal/monocular/client.go @@ -26,7 +26,6 @@ var ErrHostnameNotProvided = errors.New("no hostname provided") // Client represents a client capable of communicating with the Monocular API. type Client struct { - // The base URL for requests BaseURL string } diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index df8385ed6..3ae813b14 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -173,7 +173,7 @@ func TestExtract(t *testing.T) { // Write a tarball to a buffer for us to extract var tarbuf bytes.Buffer tw := tar.NewWriter(&tarbuf) - var files = []struct { + files := []struct { Name, Body string Mode int64 }{ @@ -293,7 +293,7 @@ func TestExtractWithNestedDirectories(t *testing.T) { // Write a tarball with nested directory structure var tarbuf bytes.Buffer tw := tar.NewWriter(&tarbuf) - var files = []struct { + files := []struct { Name string Body string Mode int64 diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 82401d069..0fee301a4 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -105,6 +105,7 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { } require.EqualErrorf(t, err, fmt.Sprintf("requested version %q does not exist for plugin %q", version, source), "expected error for version does not exists") } + func TestVCSInstallerUpdate(t *testing.T) { ensure.HelmHome(t) diff --git a/internal/plugin/loader.go b/internal/plugin/loader.go index cfa618f39..af9e175b4 100644 --- a/internal/plugin/loader.go +++ b/internal/plugin/loader.go @@ -216,7 +216,6 @@ func findPlugins(pluginsDirs []string, findFn findFunc, filterFn filterFunc) ([] var found []Plugin for _, pluginsDir := range pluginsDirs { ps, err := findFn(pluginsDir) - if err != nil { return nil, err } diff --git a/internal/plugin/metadata.go b/internal/plugin/metadata.go index 53d6da4e6..ad42fe98a 100644 --- a/internal/plugin/metadata.go +++ b/internal/plugin/metadata.go @@ -154,8 +154,7 @@ func buildLegacyConfig(m MetadataLegacy, pluginType string) Config { func buildLegacyRuntimeConfig(m MetadataLegacy) RuntimeConfig { var protocolCommands []SubprocessProtocolCommand if len(m.Downloaders) > 0 { - protocolCommands = - make([]SubprocessProtocolCommand, 0, len(m.Downloaders)) + protocolCommands = make([]SubprocessProtocolCommand, 0, len(m.Downloaders)) for _, d := range m.Downloaders { protocolCommands = append(protocolCommands, SubprocessProtocolCommand{ Protocols: d.Protocols, diff --git a/internal/plugin/verify_test.go b/internal/plugin/verify_test.go index 4f5b26a97..ab7238973 100644 --- a/internal/plugin/verify_test.go +++ b/internal/plugin/verify_test.go @@ -26,8 +26,10 @@ import ( "helm.sh/helm/v4/pkg/provenance" ) -const testKeyFile = "../../pkg/cmd/testdata/helm-test-key.secret" -const testPubFile = "../../pkg/cmd/testdata/helm-test-key.pub" +const ( + testKeyFile = "../../pkg/cmd/testdata/helm-test-key.secret" + testPubFile = "../../pkg/cmd/testdata/helm-test-key.pub" +) const testPluginYAML = `apiVersion: v1 name: test-plugin diff --git a/internal/release/v2/release.go b/internal/release/v2/release.go index 8b8f2ee07..d32a1cdc4 100644 --- a/internal/release/v2/release.go +++ b/internal/release/v2/release.go @@ -22,8 +22,10 @@ import ( type ApplyMethod string -const ApplyMethodClientSideApply ApplyMethod = "csa" -const ApplyMethodServerSideApply ApplyMethod = "ssa" +const ( + ApplyMethodClientSideApply ApplyMethod = "csa" + ApplyMethodServerSideApply ApplyMethod = "ssa" +) // Release describes a deployment of a chart, together with the chart // and the variables used to deploy that chart. diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index 6cf529bff..e132ef072 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -61,7 +61,8 @@ metadata: annotations: "helm.sh/hook": post-install `, - }, { + }, + { name: []string{"third"}, path: "three", kind: []string{"ReplicaSet"}, @@ -73,7 +74,8 @@ metadata: annotations: "helm.sh/hook": no-such-hook `, - }, { + }, + { name: []string{"fourth"}, path: "four", kind: []string{"Pod"}, @@ -84,7 +86,8 @@ metadata: name: fourth annotations: nothing: here`, - }, { + }, + { name: []string{"fifth"}, path: "five", kind: []string{"ReplicaSet"}, @@ -96,14 +99,16 @@ metadata: annotations: "helm.sh/hook": post-delete, post-install `, - }, { + }, + { // Regression test: files with an underscore in the base name should be skipped. name: []string{"sixth"}, path: "six/_six", kind: []string{"ReplicaSet"}, hooks: map[string][]release.HookEvent{"sixth": nil}, manifest: `invalid manifest`, // This will fail if partial is not skipped. - }, { + }, + { // Regression test: files with no content should be skipped. name: []string{"seventh"}, path: "seven", diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index d777b6af4..eb910d6c7 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -126,7 +126,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) { t.Skip("skipping on windows") } - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible @@ -155,7 +155,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { t.Skip("skipping on windows") } - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible @@ -217,7 +217,7 @@ func TestCopyDirFailOpen(t *testing.T) { t.Skip("skipping on windows") } - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible @@ -319,7 +319,7 @@ func TestCopyFileFail(t *testing.T) { t.Skip("skipping on windows") } - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible @@ -389,7 +389,7 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() { } func TestIsDir(t *testing.T) { - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible @@ -441,7 +441,7 @@ func TestIsDir(t *testing.T) { } func TestIsSymlink(t *testing.T) { - var currentUID = os.Getuid() + currentUID := os.Getuid() if currentUID == 0 { // Skipping if root, because all files are accessible diff --git a/internal/tlsutil/tls.go b/internal/tlsutil/tls.go index e986e6909..d0123daf5 100644 --- a/internal/tlsutil/tls.go +++ b/internal/tlsutil/tls.go @@ -19,10 +19,9 @@ package tlsutil import ( "crypto/tls" "crypto/x509" + "errors" "fmt" "os" - - "errors" ) type TLSConfigOptions struct { diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index f8851e456..9e32d840c 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -546,7 +546,7 @@ func TestMetadata_FormattedDepNames(t *testing.T) { } func convertDeps(deps []*chart.Dependency) []ci.Dependency { - var newDeps = make([]ci.Dependency, len(deps)) + newDeps := make([]ci.Dependency, len(deps)) for i, c := range deps { newDeps[i] = c } diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index d7824d69f..3c434e291 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -34,7 +34,8 @@ import ( // execHook executes all of the hooks for the given hook event. func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, - timeout time.Duration, serverSideApply bool) error { + timeout time.Duration, serverSideApply bool, +) error { shutdown, err := cfg.execHookWithDelayedShutdown(rl, hook, waitStrategy, waitOptions, timeout, serverSideApply) if shutdown == nil { return err @@ -57,7 +58,8 @@ func shutdownNoOp() error { // execHookWithDelayedShutdown executes all of the hooks for the given hook event and returns a shutdownHook function to trigger deletions after doing other things like e.g. retrieving logs. func (cfg *Configuration) execHookWithDelayedShutdown(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, timeout time.Duration, - serverSideApply bool) (ExecuteShutdownFunc, error) { + serverSideApply bool, +) (ExecuteShutdownFunc, error) { executingHooks := []*release.Hook{} for _, h := range rl.Hooks { @@ -176,7 +178,8 @@ func (x hookByWeight) Less(i, j int) bool { // deleteHookByPolicy deletes a hook if the hook policy instructs it to func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.HookDeletePolicy, - waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, timeout time.Duration) error { + waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, timeout time.Duration, +) error { // Never delete CustomResourceDefinitions; this could cause lots of // cascading garbage collection. if h.Kind == "CustomResourceDefinition" { @@ -210,7 +213,8 @@ func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.Hoo // deleteHooksByPolicy deletes all hooks if the hook policy instructs it to func (cfg *Configuration) deleteHooksByPolicy(hooks []*release.Hook, policy release.HookDeletePolicy, - waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, timeout time.Duration) error { + waitStrategy kube.WaitStrategy, waitOptions []kube.WaitOption, timeout time.Duration, +) error { for _, h := range hooks { if err := cfg.deleteHookByPolicy(h, policy, waitStrategy, waitOptions, timeout); err != nil { return err diff --git a/pkg/action/hooks_test.go b/pkg/action/hooks_test.go index ad3a4b618..4cb176d36 100644 --- a/pkg/action/hooks_test.go +++ b/pkg/action/hooks_test.go @@ -252,7 +252,6 @@ func (*HookFailingKubeClient) Build(reader io.Reader, _ bool) (kube.ResourceList configMap := &v1.ConfigMap{} err := yaml.NewYAMLOrJSONDecoder(reader, 1000).Decode(configMap) - if err != nil { return kube.ResourceList{}, err } @@ -358,10 +357,12 @@ data: }, }, }, - }, resource.Info{ + }, + resource.Info{ Name: "build-config-2", Namespace: "test", - }, []resource.Info{ + }, + []resource.Info{ { // This should be in the record for `before-hook-creation` Name: "build-config-1", @@ -382,7 +383,8 @@ data: Name: "build-config-1", Namespace: "test", }, - }, true, + }, + true, }, } diff --git a/pkg/action/install.go b/pkg/action/install.go index d73eca619..605c423bc 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -733,7 +733,6 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er defer f.Close() _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, data) - if err != nil { return err } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 4dbeb7c79..80f3bd724 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -631,6 +631,7 @@ func TestInstallRelease_Wait(t *testing.T) { is.Equal(goroutines, instAction.getGoroutineCount()) } + func TestInstallRelease_Wait_Interrupted(t *testing.T) { is := assert.New(t) req := require.New(t) @@ -655,6 +656,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { time.Sleep(10 * time.Second) // wait for goroutine to finish is.Equal(goroutines, instAction.getGoroutineCount()) } + func TestInstallRelease_WaitForJobs(t *testing.T) { is := assert.New(t) req := require.New(t) @@ -722,6 +724,7 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { is.ErrorContains(err, "an error occurred while uninstalling the release") }) } + func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { is := assert.New(t) req := require.New(t) @@ -754,6 +757,7 @@ func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { time.Sleep(10 * time.Second) // wait for goroutine to finish is.Equal(goroutines, instAction.getGoroutineCount()) } + func TestNameTemplate(t *testing.T) { testCases := []nameTemplateTestCase{ // Just a straight up nop please diff --git a/pkg/action/list.go b/pkg/action/list.go index a055f760d..7902837fd 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -172,7 +172,6 @@ func (l *List) Run() ([]ri.Releaser, error) { return true }) - if err != nil { return nil, err } @@ -264,7 +263,7 @@ func filterLatestReleases(releases []*release.Release) []*release.Release { latestReleases[key] = rls } - var list = make([]*release.Release, 0, len(latestReleases)) + list := make([]*release.Release, 0, len(latestReleases)) for _, rls := range latestReleases { list = append(list, rls) } diff --git a/pkg/action/release_testing.go b/pkg/action/release_testing.go index 5604e8cc4..6edb644c1 100644 --- a/pkg/action/release_testing.go +++ b/pkg/action/release_testing.go @@ -107,7 +107,6 @@ func (r *ReleaseTesting) Run(name string) (ri.Releaser, ExecuteShutdownFunc, err serverSideApply := rel.ApplyMethod == string(release.ApplyMethodServerSideApply) shutdown, err := r.cfg.execHookWithDelayedShutdown(rel, release.HookTest, kube.StatusWatcherStrategy, r.WaitOptions, r.Timeout, serverSideApply) - if err != nil { rel.Hooks = append(skippedHooks, rel.Hooks...) r.cfg.Releases.Update(reli) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 6fc449c30..f2cdaf177 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -232,7 +232,6 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas kube.ClientUpdateOptionServerSideApply(serverSideApply, r.ForceConflicts), kube.ClientUpdateOptionThreeWayMergeForUnstructured(false), kube.ClientUpdateOptionUpgradeClientSideFieldManager(true)) - if err != nil { msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) r.cfg.Logger().Warn(msg) diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index 47b2e47de..4d2c728db 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -77,7 +77,6 @@ func (u *Uninstall) Run(name string) (*releasei.UninstallReleaseResponse, error) if u.DryRun { ri, err := u.cfg.releaseContent(name, 0) - if err != nil { if u.IgnoreNotFound && errors.Is(err, driver.ErrReleaseNotFound) { return nil, nil diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index f36fe7874..e306935c7 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -59,6 +59,7 @@ func TestUninstallRelease_ignoreNotFound(t *testing.T) { is.Nil(res) is.NoError(err) } + func TestUninstallRelease_deleteRelease(t *testing.T) { is := assert.New(t) req := require.New(t) diff --git a/pkg/chart/common.go b/pkg/chart/common.go index cec2c7091..be68eeb42 100644 --- a/pkg/chart/common.go +++ b/pkg/chart/common.go @@ -85,7 +85,7 @@ func (r *v2Accessor) IsLibraryChart() bool { } func (r *v2Accessor) Dependencies() []Charter { - var deps = make([]Charter, len(r.chrt.Dependencies())) + deps := make([]Charter, len(r.chrt.Dependencies())) for i, c := range r.chrt.Dependencies() { deps[i] = c } @@ -93,7 +93,7 @@ func (r *v2Accessor) Dependencies() []Charter { } func (r *v2Accessor) MetaDependencies() []Dependency { - var deps = make([]Dependency, len(r.chrt.Metadata.Dependencies)) + deps := make([]Dependency, len(r.chrt.Metadata.Dependencies)) for i, c := range r.chrt.Metadata.Dependencies { deps[i] = c } @@ -154,7 +154,7 @@ func (r *v3Accessor) IsLibraryChart() bool { } func (r *v3Accessor) Dependencies() []Charter { - var deps = make([]Charter, len(r.chrt.Dependencies())) + deps := make([]Charter, len(r.chrt.Dependencies())) for i, c := range r.chrt.Dependencies() { deps[i] = c } @@ -162,7 +162,7 @@ func (r *v3Accessor) Dependencies() []Charter { } func (r *v3Accessor) MetaDependencies() []Dependency { - var deps = make([]Dependency, len(r.chrt.Dependencies())) + deps := make([]Dependency, len(r.chrt.Dependencies())) for i, c := range r.chrt.Metadata.Dependencies { deps[i] = c } diff --git a/pkg/chart/common/capabilities.go b/pkg/chart/common/capabilities.go index 16910acaa..a9374a86f 100644 --- a/pkg/chart/common/capabilities.go +++ b/pkg/chart/common/capabilities.go @@ -47,7 +47,6 @@ var ( panic(fmt.Sprintf("failed to create default capabilities: %v", err)) } return caps - }() ) diff --git a/pkg/chart/v2/lint/lint_test.go b/pkg/chart/v2/lint/lint_test.go index c4705872d..8ff88b05c 100644 --- a/pkg/chart/v2/lint/lint_test.go +++ b/pkg/chart/v2/lint/lint_test.go @@ -30,14 +30,16 @@ import ( const namespace = "testNamespace" -const badChartDir = "rules/testdata/badchartfile" -const badValuesFileDir = "rules/testdata/badvaluesfile" -const badYamlFileDir = "rules/testdata/albatross" -const badCrdFileDir = "rules/testdata/badcrdfile" -const goodChartDir = "rules/testdata/goodone" -const subChartValuesDir = "rules/testdata/withsubchart" -const malformedTemplate = "rules/testdata/malformed-template" -const invalidChartFileDir = "rules/testdata/invalidchartfile" +const ( + badChartDir = "rules/testdata/badchartfile" + badValuesFileDir = "rules/testdata/badvaluesfile" + badYamlFileDir = "rules/testdata/albatross" + badCrdFileDir = "rules/testdata/badcrdfile" + goodChartDir = "rules/testdata/goodone" + subChartValuesDir = "rules/testdata/withsubchart" + malformedTemplate = "rules/testdata/malformed-template" + invalidChartFileDir = "rules/testdata/invalidchartfile" +) func TestBadChart(t *testing.T) { var values map[string]any diff --git a/pkg/chart/v2/lint/rules/chartfile.go b/pkg/chart/v2/lint/rules/chartfile.go index f867daa21..ec4083951 100644 --- a/pkg/chart/v2/lint/rules/chartfile.go +++ b/pkg/chart/v2/lint/rules/chartfile.go @@ -161,7 +161,6 @@ func validateChartVersion(cf *chart.Metadata) error { func validateChartVersionStrictSemVerV2(cf *chart.Metadata) error { _, err := semver.StrictNewVersion(cf.Version) - if err != nil { return fmt.Errorf("version '%s' is not a valid SemVerV2", cf.Version) } diff --git a/pkg/chart/v2/lint/rules/chartfile_test.go b/pkg/chart/v2/lint/rules/chartfile_test.go index 1cc331a74..90f5edd5c 100644 --- a/pkg/chart/v2/lint/rules/chartfile_test.go +++ b/pkg/chart/v2/lint/rules/chartfile_test.go @@ -42,8 +42,10 @@ var ( nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml") ) -var badChart, _ = chartutil.LoadChartfile(badChartFilePath) -var badChartName, _ = chartutil.LoadChartfile(badChartNamePath) +var ( + badChart, _ = chartutil.LoadChartfile(badChartFilePath) + badChartName, _ = chartutil.LoadChartfile(badChartNamePath) +) // Validation functions Test func TestValidateChartYamlNotDirectory(t *testing.T) { @@ -63,7 +65,7 @@ func TestValidateChartName(t *testing.T) { } func TestValidateChartVersion(t *testing.T) { - var failTest = []struct { + failTest := []struct { Version string ErrorMsg string }{ @@ -73,7 +75,7 @@ func TestValidateChartVersion(t *testing.T) { {"-3", "'-3' is not a valid SemVer"}, } - var successTest = []string{"0.0.1", "0.0.1+build", "0.0.1-beta"} + successTest := []string{"0.0.1", "0.0.1+build", "0.0.1-beta"} for _, test := range failTest { badChart.Version = test.Version @@ -87,7 +89,7 @@ func TestValidateChartVersion(t *testing.T) { } func TestValidateChartVersionStrictSemVerV2(t *testing.T) { - var failTest = []struct { + failTest := []struct { Version string ErrorMsg string }{ @@ -96,7 +98,7 @@ func TestValidateChartVersionStrictSemVerV2(t *testing.T) { {"1.1", "version '1.1' is not a valid SemVerV2"}, } - var successTest = []string{"1.1.1", "0.0.1+build", "0.0.1-beta"} + successTest := []string{"1.1.1", "0.0.1+build", "0.0.1-beta"} for _, test := range failTest { badChart.Version = test.Version @@ -110,7 +112,7 @@ func TestValidateChartVersionStrictSemVerV2(t *testing.T) { } func TestValidateChartMaintainer(t *testing.T) { - var failTest = []struct { + failTest := []struct { Name string Email string ErrorMsg string @@ -120,7 +122,7 @@ func TestValidateChartMaintainer(t *testing.T) { {"John Snow", "wrongFormatEmail.com", "invalid email"}, } - var successTest = []struct { + successTest := []struct { Name string Email string }{ @@ -144,8 +146,8 @@ func TestValidateChartMaintainer(t *testing.T) { } func TestValidateChartSources(t *testing.T) { - var failTest = []string{"", "RiverRun", "john@winterfell", "riverrun.io"} - var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} + failTest := []string{"", "RiverRun", "john@winterfell", "riverrun.io"} + successTest := []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} for _, test := range failTest { badChart.Sources = []string{test} require.ErrorContainsf(t, validateChartSources(badChart), "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) @@ -174,8 +176,8 @@ func TestValidateChartIconPresence(t *testing.T) { } func TestValidateChartIconURL(t *testing.T) { - var failTest = []string{"RiverRun", "john@winterfell", "riverrun.io"} - var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} + failTest := []string{"RiverRun", "john@winterfell", "riverrun.io"} + successTest := []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} for _, test := range failTest { badChart.Icon = test require.ErrorContainsf(t, validateChartIconURL(badChart), "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index ab78450b9..3f350557b 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -35,11 +35,11 @@ import ( const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { - var failTest = []string{"/foo", "/test.toml"} + failTest := []string{"/foo", "/test.toml"} for _, test := range failTest { require.ErrorContainsf(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } - var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} + successTest := []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } @@ -62,8 +62,10 @@ func TestTemplateParsing(t *testing.T) { assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } -var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") -var ignoredTemplatePath = filepath.Join(templateTestBasedir, "fail.yaml.ignored") +var ( + wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") + ignoredTemplatePath = filepath.Join(templateTestBasedir, "fail.yaml.ignored") +) // Test a template with all the existing features: // namespaces, partial templates @@ -406,6 +408,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } require.Empty(t, linter.Messages, "Expected 0 lint errors") } + func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ APIVersion: "v1", diff --git a/pkg/chart/v2/lint/support/message_test.go b/pkg/chart/v2/lint/support/message_test.go index 6d09df688..8a4783605 100644 --- a/pkg/chart/v2/lint/support/message_test.go +++ b/pkg/chart/v2/lint/support/message_test.go @@ -27,7 +27,7 @@ import ( var errLint = errors.New("lint failed") func TestRunLinterRule(t *testing.T) { - var tests = []struct { + tests := []struct { Severity int LintError error ExpectedMessages int diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index 4d73cb0d6..8bf254321 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -182,7 +182,8 @@ func TestLoadFiles_BadCases(t *testing.T) { Data: []byte(""), }, }, - expectError: "validation: chart.metadata.apiVersion is required"}, + expectError: "validation: chart.metadata.apiVersion is required", + }, } { _, err := LoadFiles(tt.bufferedFiles) require.Error(t, err, "expected error when load illegal files") diff --git a/pkg/cmd/completion.go b/pkg/cmd/completion.go index c02462d9d..5edac8f44 100644 --- a/pkg/cmd/completion.go +++ b/pkg/cmd/completion.go @@ -29,6 +29,7 @@ import ( const completionDesc = ` Generate autocompletion scripts for Helm for the specified shell. ` + const bashCompDesc = ` Generate the autocompletion script for Helm for the bash shell. diff --git a/pkg/cmd/dependency_build_test.go b/pkg/cmd/dependency_build_test.go index 485ae18b3..1680c23a1 100644 --- a/pkg/cmd/dependency_build_test.go +++ b/pkg/cmd/dependency_build_test.go @@ -59,7 +59,6 @@ func TestDependencyBuildCmd(t *testing.T) { cmd := fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir) _, out, err := executeActionCommand(cmd) - // In the first pass, we basically want the same results as an update. if err != nil { t.Logf("Output: %s", out) @@ -105,7 +104,6 @@ func TestDependencyBuildCmd(t *testing.T) { skipRefreshCmd := fmt.Sprintf("dependency build '%s' --skip-refresh --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir) _, out, err = executeActionCommand(skipRefreshCmd) - // In this pass, we check --skip-refresh option becomes effective. if err != nil { t.Logf("Output: %s", out) @@ -136,7 +134,6 @@ func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) { cmd := fmt.Sprintf("dependency build '%s'", chartName) _, out, err := executeActionCommand(cmd) - // Want to make sure the build can verify Helm v2 hash if err != nil { t.Logf("Output: %s", out) diff --git a/pkg/cmd/dependency_test.go b/pkg/cmd/dependency_test.go index d6bcebf1b..48ab78183 100644 --- a/pkg/cmd/dependency_test.go +++ b/pkg/cmd/dependency_test.go @@ -39,16 +39,20 @@ func TestDependencyListCmd(t *testing.T) { noDependencies.golden = "output/dependency-list-no-requirements-windows.txt" } - tests := []cmdTestCase{noSuchChart, - noDependencies, { + tests := []cmdTestCase{ + noSuchChart, + noDependencies, + { name: "Dependencies in chart dir", cmd: "dependency list testdata/testcharts/reqtest", golden: "output/dependency-list.txt", - }, { + }, + { name: "Dependencies in chart archive", cmd: "dependency list testdata/testcharts/reqtest-0.1.0.tgz", golden: "output/dependency-list-archive.txt", - }} + }, + } runTestCmd(t, tests) } diff --git a/pkg/cmd/dependency_update_test.go b/pkg/cmd/dependency_update_test.go index 13eb74532..34575ad4d 100644 --- a/pkg/cmd/dependency_update_test.go +++ b/pkg/cmd/dependency_update_test.go @@ -209,7 +209,6 @@ func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --content-cache %s", dir(chartname), dir("repositories.yaml"), dir(), contentCache), ) - if err != nil { t.Logf("Output: %s", out) t.Fatal(err) diff --git a/pkg/cmd/flags.go b/pkg/cmd/flags.go index e59487044..45da90d0e 100644 --- a/pkg/cmd/flags.go +++ b/pkg/cmd/flags.go @@ -152,7 +152,6 @@ func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) { sort.Strings(formatNames) return formatNames, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/get_hooks.go b/pkg/cmd/get_hooks.go index d344307cb..4d174675f 100644 --- a/pkg/cmd/get_hooks.go +++ b/pkg/cmd/get_hooks.go @@ -75,7 +75,6 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/get_manifest.go b/pkg/cmd/get_manifest.go index 253b011c1..a7873e587 100644 --- a/pkg/cmd/get_manifest.go +++ b/pkg/cmd/get_manifest.go @@ -71,7 +71,6 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/get_metadata.go b/pkg/cmd/get_metadata.go index c26af646f..ffbe25f99 100644 --- a/pkg/cmd/get_metadata.go +++ b/pkg/cmd/get_metadata.go @@ -66,7 +66,6 @@ func newGetMetadataCmd(cfg *action.Configuration, out io.Writer) *cobra.Command } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/get_notes.go b/pkg/cmd/get_notes.go index 7f8754f3c..b6172846f 100644 --- a/pkg/cmd/get_notes.go +++ b/pkg/cmd/get_notes.go @@ -70,7 +70,6 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/get_values.go b/pkg/cmd/get_values.go index c6a89b00c..5db5dec3a 100644 --- a/pkg/cmd/get_values.go +++ b/pkg/cmd/get_values.go @@ -69,7 +69,6 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/load_plugins.go b/pkg/cmd/load_plugins.go index dee42f750..0c74ba51d 100644 --- a/pkg/cmd/load_plugins.go +++ b/pkg/cmd/load_plugins.go @@ -221,7 +221,6 @@ type pluginCommand struct { func loadCompletionForPlugin(pluginCmd *cobra.Command, plug plugin.Plugin) { // Parse the yaml file providing the plugin's sub-commands and flags cmds, err := loadFile(plug.Dir() + string(filepath.Separator) + pluginStaticCompletionFile) - if err != nil { // The file could be missing or invalid. No static completion for this plugin. slog.Debug("plugin completion file loading", slog.String("error", err.Error())) diff --git a/pkg/cmd/pull.go b/pkg/cmd/pull.go index d371db4ad..9f5af462b 100644 --- a/pkg/cmd/pull.go +++ b/pkg/cmd/pull.go @@ -97,7 +97,6 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return compVersionFlag(args[0], toComplete) }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index d0371710b..a62d6b1b4 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -268,7 +268,8 @@ func runPullTests(t *testing.T, tests []struct { wantErrorMsg string expectFile string expectDir bool -}, outdir string, additionalFlags string) { +}, outdir string, additionalFlags string, +) { t.Helper() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/cmd/push.go b/pkg/cmd/push.go index f32ce92be..df0bad643 100644 --- a/pkg/cmd/push.go +++ b/pkg/cmd/push.go @@ -73,7 +73,6 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { registryClient, err := newRegistryClient( out, o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSVerify, o.plainHTTP, o.username, o.password, ) - if err != nil { return fmt.Errorf("missing registry client: %w", err) } diff --git a/pkg/cmd/repo_remove_test.go b/pkg/cmd/repo_remove_test.go index 7d252c35d..f58bc91d9 100644 --- a/pkg/cmd/repo_remove_test.go +++ b/pkg/cmd/repo_remove_test.go @@ -76,7 +76,7 @@ func TestRepoRemove(t *testing.T) { assert.Falsef(t, f.Has(testRepoName), "%s was not successfully removed from repositories list", testRepoName) // Test removal of multiple repos in one go - var testRepoNames = []string{"foo", "bar", "baz"} + testRepoNames := []string{"foo", "bar", "baz"} cacheFiles := make(map[string][]string, len(testRepoNames)) // Add test repos @@ -151,7 +151,7 @@ func TestRepoRemoveCompletion(t *testing.T) { repoFile := filepath.Join(rootDir, "repositories.yaml") repoCache := filepath.Join(rootDir, "cache") - var testRepoNames = []string{"foo", "bar", "baz"} + testRepoNames := []string{"foo", "bar", "baz"} // Add test repos for _, repoName := range testRepoNames { diff --git a/pkg/cmd/repo_update_test.go b/pkg/cmd/repo_update_test.go index 70b6dfbef..e8d7ad64a 100644 --- a/pkg/cmd/repo_update_test.go +++ b/pkg/cmd/repo_update_test.go @@ -159,7 +159,7 @@ func TestUpdateChartsFailWithError(t *testing.T) { ) defer ts.Stop() - var invalidURL = ts.URL() + "55" + invalidURL := ts.URL() + "55" r1, err := repo.NewChartRepository(&repo.Entry{ Name: "charts", URL: invalidURL, diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 410a9162c..dbedca026 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -229,7 +229,6 @@ func newRootCmdWithConfig(actionConfig *action.Configuration, out io.Writer, arg } return nil, cobra.ShellCompDirectiveDefault }) - if err != nil { log.Fatal(err) } @@ -253,7 +252,6 @@ func newRootCmdWithConfig(actionConfig *action.Configuration, out io.Writer, arg } return nil, cobra.ShellCompDirectiveNoFileComp }) - if err != nil { log.Fatal(err) } @@ -446,7 +444,6 @@ func newRegistryClientWithTLS( tlsutil.WithCertKeyPairFiles(certFile, keyFile), tlsutil.WithCAFile(caFile), ) - if err != nil { return nil, fmt.Errorf("can't create TLS config for client: %w", err) } diff --git a/pkg/cmd/search_hub_test.go b/pkg/cmd/search_hub_test.go index a1612443a..8bc5e78af 100644 --- a/pkg/cmd/search_hub_test.go +++ b/pkg/cmd/search_hub_test.go @@ -28,7 +28,7 @@ import ( func TestSearchHubCmd(t *testing.T) { // Setup a mock search service - var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` + searchResult := `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { fmt.Fprintln(w, searchResult) })) @@ -37,7 +37,7 @@ func TestSearchHubCmd(t *testing.T) { // The expected output has the URL to the mocked search service in it // Trailing spaces are necessary to preserve in "expected" as the uitable package adds // them during printing. - var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION + expected := fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend `, ts.URL, ts.URL) @@ -51,7 +51,7 @@ func TestSearchHubCmd(t *testing.T) { func TestSearchHubListRepoCmd(t *testing.T) { // Setup a mock search service - var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` + searchResult := `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { fmt.Fprintln(w, searchResult) })) @@ -60,7 +60,7 @@ func TestSearchHubListRepoCmd(t *testing.T) { // The expected output has the URL to the mocked search service in it // Trailing spaces are necessary to preserve in "expected" as the uitable package adds // them during printing. - var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO URL + expected := fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO URL %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.helm.sh/stable %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.bitnami.com `, ts.URL, ts.URL) @@ -96,7 +96,7 @@ func TestSearchHubCmd_FailOnNoResponseTests(t *testing.T) { wantErr bool } - var tests = []testCase{ + tests := []testCase{ { name: "Search hub with no results in response", cmd: `search hub maria`, diff --git a/pkg/cmd/search_repo_test.go b/pkg/cmd/search_repo_test.go index e7f104e05..e28984fd8 100644 --- a/pkg/cmd/search_repo_test.go +++ b/pkg/cmd/search_repo_test.go @@ -61,7 +61,8 @@ func TestSearchRepositoriesCmd(t *testing.T) { cmd: "search repo syzygy --fail-on-no-result", golden: "output/search-not-found-error.txt", wantError: true, - }, {name: "search for 'syzygy' with json output and --fail-on-no-result, expect failure for no results", + }, { + name: "search for 'syzygy' with json output and --fail-on-no-result, expect failure for no results", cmd: "search repo syzygy --output json --fail-on-no-result", golden: "output/search-not-found-error.txt", wantError: true, diff --git a/pkg/cmd/show.go b/pkg/cmd/show.go index a92ca75b4..8252d933e 100644 --- a/pkg/cmd/show.go +++ b/pkg/cmd/show.go @@ -205,7 +205,6 @@ func addShowFlags(subCmd *cobra.Command, client *action.Show) { } return compVersionFlag(args[0], toComplete) }) - if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/status_test.go b/pkg/cmd/status_test.go index b96a0d19a..2e1a5579e 100644 --- a/pkg/cmd/status_test.go +++ b/pkg/cmd/status_test.go @@ -185,7 +185,8 @@ func TestStatusCompletion(t *testing.T) { Version: "1.2.3-prerelease", }, }, - }} + }, + } tests := []cmdTestCase{{ name: "completion for status", diff --git a/pkg/cmd/template.go b/pkg/cmd/template.go index ccc1db719..29839b871 100644 --- a/pkg/cmd/template.go +++ b/pkg/cmd/template.go @@ -254,7 +254,6 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er defer f.Close() _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, data) - if err != nil { return err } diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 1d0affd93..67b1cf47b 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -143,9 +143,11 @@ type renderable struct { basePath string } -const warnStartDelim = "HELM_ERR_START" -const warnEndDelim = "HELM_ERR_END" -const recursionMaxNums = 1000 +const ( + warnStartDelim = "HELM_ERR_START" + warnEndDelim = "HELM_ERR_END" + recursionMaxNums = 1000 +) var warnRegex = regexp.MustCompile(warnStartDelim + `((?s).*)` + warnEndDelim) diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 1f3096366..14faeeb63 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -1278,6 +1278,7 @@ func TestTraceableError_SimpleForm(t *testing.T) { assert.Equal(t, "error calling include", trace.message, "Expected %q, got %q", errString, trace.message) } } + func TestTraceableError_ExecutingForm(t *testing.T) { testStrings := [][]string{ {"function_not_found/templates/secret.yaml:6:11: executing \"function_not_found/templates/secret.yaml\" at : ", "function_not_found/templates/secret.yaml:6:11"}, diff --git a/pkg/engine/funcs.go b/pkg/engine/funcs.go index 431f82f63..04a48cad3 100644 --- a/pkg/engine/funcs.go +++ b/pkg/engine/funcs.go @@ -130,7 +130,6 @@ func toYAMLPretty(v any) string { encoder := goYaml.NewEncoder(&data) encoder.SetIndent(2) err := encoder.Encode(v) - if err != nil { // Swallow errors inside of a template. return "" diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index beb87b429..03ed64153 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -147,39 +147,40 @@ keyInElement1 = "valueInElement1"`, tpl string expect any vars any - }{{ - tpl: `{{ mustToYaml . }}`, - vars: loopMap, - }, { - tpl: `{{ mustToJson . }}`, - vars: loopMap, - }, { - tpl: `{{ mustToDuration 30 }}`, - expect: `30s`, - vars: nil, - }, { - tpl: `{{ mustToDuration "1m30s" }}`, - expect: `1m30s`, - vars: nil, - }, { - tpl: `{{ mustToDuration "foo" }}`, - vars: nil, - }, { - tpl: `{{ toYaml . }}`, - expect: "", // should return empty string and swallow error - vars: loopMap, - }, { - tpl: `{{ toJson . }}`, - expect: "", // should return empty string and swallow error - vars: loopMap, - }, { - tpl: `{{ mustToToml . }}`, - vars: map[int]string{1: "one"}, // non-string key is invalid in TOML - }, { - tpl: `{{ mustToToml . }}`, - expect: "foo = \"bar\"\n", // should succeed and return TOML string - vars: map[string]string{"foo": "bar"}, - }, + }{ + { + tpl: `{{ mustToYaml . }}`, + vars: loopMap, + }, { + tpl: `{{ mustToJson . }}`, + vars: loopMap, + }, { + tpl: `{{ mustToDuration 30 }}`, + expect: `30s`, + vars: nil, + }, { + tpl: `{{ mustToDuration "1m30s" }}`, + expect: `1m30s`, + vars: nil, + }, { + tpl: `{{ mustToDuration "foo" }}`, + vars: nil, + }, { + tpl: `{{ toYaml . }}`, + expect: "", // should return empty string and swallow error + vars: loopMap, + }, { + tpl: `{{ toJson . }}`, + expect: "", // should return empty string and swallow error + vars: loopMap, + }, { + tpl: `{{ mustToToml . }}`, + vars: map[int]string{1: "one"}, // non-string key is invalid in TOML + }, { + tpl: `{{ mustToToml . }}`, + expect: "foo = \"bar\"\n", // should succeed and return TOML string + vars: map[string]string{"foo": "bar"}, + }, } for _, tt := range mustFuncsTests { @@ -368,48 +369,49 @@ func TestDurationHelpers(t *testing.T) { name string tpl string vars any - }{{ - name: "mustToDuration invalid string", - tpl: `{{ mustToDuration "nope" }}`, - }, { - name: "mustToDuration empty string", - tpl: `{{ mustToDuration "" }}`, - }, { - name: "mustToDuration whitespace string", - tpl: `{{ mustToDuration " " }}`, - }, { - name: "mustToDuration unsupported type", - tpl: `{{ mustToDuration . }}`, - vars: []int{1, 2, 3}, - }, { - name: "mustToDuration uint overflow", - tpl: `{{ mustToDuration . }}`, - vars: uint64(math.MaxInt64) + 1, - }, { - name: "mustToDuration int overflow", - tpl: `{{ mustToDuration . }}`, - vars: maxDurationSeconds + 1, - }, { - name: "mustToDuration int underflow", - tpl: `{{ mustToDuration . }}`, - vars: minDurationSeconds - 1, - }, { - name: "mustToDuration float overflow", - tpl: `{{ mustToDuration . }}`, - vars: maxDurationSecondsFloat + 0.5, - }, { - name: "mustToDuration float underflow", - tpl: `{{ mustToDuration . }}`, - vars: minDurationSecondsFloat - 0.5, - }, { - name: "mustToDuration NaN", - tpl: `{{ mustToDuration . }}`, - vars: math.NaN(), - }, { - name: "mustToDuration Inf", - tpl: `{{ mustToDuration . }}`, - vars: math.Inf(-1), - }, + }{ + { + name: "mustToDuration invalid string", + tpl: `{{ mustToDuration "nope" }}`, + }, { + name: "mustToDuration empty string", + tpl: `{{ mustToDuration "" }}`, + }, { + name: "mustToDuration whitespace string", + tpl: `{{ mustToDuration " " }}`, + }, { + name: "mustToDuration unsupported type", + tpl: `{{ mustToDuration . }}`, + vars: []int{1, 2, 3}, + }, { + name: "mustToDuration uint overflow", + tpl: `{{ mustToDuration . }}`, + vars: uint64(math.MaxInt64) + 1, + }, { + name: "mustToDuration int overflow", + tpl: `{{ mustToDuration . }}`, + vars: maxDurationSeconds + 1, + }, { + name: "mustToDuration int underflow", + tpl: `{{ mustToDuration . }}`, + vars: minDurationSeconds - 1, + }, { + name: "mustToDuration float overflow", + tpl: `{{ mustToDuration . }}`, + vars: maxDurationSecondsFloat + 0.5, + }, { + name: "mustToDuration float underflow", + tpl: `{{ mustToDuration . }}`, + vars: minDurationSecondsFloat - 0.5, + }, { + name: "mustToDuration NaN", + tpl: `{{ mustToDuration . }}`, + vars: math.NaN(), + }, { + name: "mustToDuration Inf", + tpl: `{{ mustToDuration . }}`, + vars: math.Inf(-1), + }, } for _, tt := range mustErrTests { diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index de8643bcd..b890d05d7 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -165,7 +165,6 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) { } client, err := registry.NewClient(opts...) - if err != nil { return nil, err } diff --git a/pkg/getter/plugingetter.go b/pkg/getter/plugingetter.go index c683a1090..0e048ccb3 100644 --- a/pkg/getter/plugingetter.go +++ b/pkg/getter/plugingetter.go @@ -19,7 +19,6 @@ import ( "bytes" "context" "fmt" - "net/url" "helm.sh/helm/v4/internal/plugin" diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index c9ed9f779..f36f48d00 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -17,7 +17,6 @@ package getter import ( "context" - "testing" "time" diff --git a/pkg/kube/client.go b/pkg/kube/client.go index bb26fbcc9..ba881c560 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -127,8 +127,10 @@ const ( FieldValidationDirectiveStrict FieldValidationDirective = "Strict" ) -type CreateApplyFunc func(target *resource.Info) error -type UpdateApplyFunc func(original, target *resource.Info) error +type ( + CreateApplyFunc func(target *resource.Info) error + UpdateApplyFunc func(original, target *resource.Info) error +) func init() { // Add CRDs to the scheme. They are missing by default. diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 405925a30..86574a3e5 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -2260,7 +2260,8 @@ metadata: } func createManifest(t *testing.T, manifest string, - fakeMapper meta.RESTMapper, fakeClient *dynamicfake.FakeDynamicClient) { + fakeMapper meta.RESTMapper, fakeClient *dynamicfake.FakeDynamicClient, +) { t.Helper() m := make(map[string]any) diff --git a/pkg/kube/converter.go b/pkg/kube/converter.go index 7300a708c..7bdc143ac 100644 --- a/pkg/kube/converter.go +++ b/pkg/kube/converter.go @@ -28,8 +28,10 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -var k8sNativeScheme *runtime.Scheme -var k8sNativeSchemeOnce sync.Once +var ( + k8sNativeScheme *runtime.Scheme + k8sNativeSchemeOnce sync.Once +) // AsVersioned converts the given info into a runtime.Object with the correct // group and version set @@ -41,7 +43,7 @@ func AsVersioned(info *resource.Info) runtime.Object { // RESTMapping. If no mapping is provided, the default schema versioner is used func convertWithMapper(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object { s := kubernetesNativeScheme() - var gv = runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups())) + gv := runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups())) if mapping != nil { gv = mapping.GroupVersionKind.GroupVersion() } diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go index 9b3e774cb..90b7559e5 100644 --- a/pkg/provenance/sign.go +++ b/pkg/provenance/sign.go @@ -218,7 +218,6 @@ func (s *Signatory) ClearSign(archiveData []byte, filename string, metadataBytes } _, err = io.Copy(w, b) - if err != nil { // NB: We intentionally don't call `w.Close()` here! `w.Close()` is the method which // actually does the PGP signing, and therefore is the part which uses the private key. diff --git a/pkg/registry/client.go b/pkg/registry/client.go index d1a744f4b..4c7b9a6c8 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -329,7 +329,6 @@ func ensureTLSConfig(client *auth.Client, setConfig *tls.Config) (*tls.Config, e func LoginOptInsecure(insecure bool) LoginOption { return func(o *loginOperation) { tlsConfig, err := ensureTLSConfig(o.client.authorizer, nil) - if err != nil { panic(err) } @@ -909,7 +908,8 @@ func (c *Client) ValidateReference(ref, version string, u *url.URL) (string, *ur // tagManifest prepares and tags a manifest in memory storage func (c *Client) tagManifest(ctx context.Context, memoryStore *memory.Store, configDescriptor ocispec.Descriptor, layers []ocispec.Descriptor, - ociAnnotations map[string]string, parsedRef reference) (ocispec.Descriptor, error) { + ociAnnotations map[string]string, parsedRef reference, +) (ocispec.Descriptor, error) { manifest := ocispec.Manifest{ Versioned: specs.Versioned{SchemaVersion: 2}, Config: configDescriptor, diff --git a/pkg/registry/client_scope_test.go b/pkg/registry/client_scope_test.go index a790c27a7..733ce980d 100644 --- a/pkg/registry/client_scope_test.go +++ b/pkg/registry/client_scope_test.go @@ -40,6 +40,7 @@ func (suite *RegistryScopeTestSuite) SetupSuite() { // when the registry itself was reached over https. setup(&suite.TestRegistry, false, false, "token") } + func (suite *RegistryScopeTestSuite) TearDownSuite() { teardown(&suite.TestRegistry) os.RemoveAll(suite.WorkspaceDir) diff --git a/pkg/release/common.go b/pkg/release/common.go index 7d40effdc..eef48f099 100644 --- a/pkg/release/common.go +++ b/pkg/release/common.go @@ -77,7 +77,7 @@ func (a *v1Accessor) Version() int { } func (a *v1Accessor) Hooks() []Hook { - var hooks = make([]Hook, len(a.rel.Hooks)) + hooks := make([]Hook, len(a.rel.Hooks)) for i, h := range a.rel.Hooks { hooks[i] = h } @@ -141,7 +141,7 @@ func (a *v2Accessor) Version() int { } func (a *v2Accessor) Hooks() []Hook { - var hooks = make([]Hook, len(a.rel.Hooks)) + hooks := make([]Hook, len(a.rel.Hooks)) for i, h := range a.rel.Hooks { hooks[i] = h } diff --git a/pkg/release/v1/release.go b/pkg/release/v1/release.go index 3bbc0e4ce..bb99ec733 100644 --- a/pkg/release/v1/release.go +++ b/pkg/release/v1/release.go @@ -22,8 +22,10 @@ import ( type ApplyMethod string -const ApplyMethodClientSideApply ApplyMethod = "csa" -const ApplyMethodServerSideApply ApplyMethod = "ssa" +const ( + ApplyMethodClientSideApply ApplyMethod = "csa" + ApplyMethodServerSideApply ApplyMethod = "ssa" +) // Release describes a deployment of a chart, together with the chart // and the variables used to deploy that chart. diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index da08ab169..bdb36786f 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -61,7 +61,8 @@ metadata: annotations: "helm.sh/hook": post-install `, - }, { + }, + { name: []string{"third"}, path: "three", kind: []string{"ReplicaSet"}, @@ -73,7 +74,8 @@ metadata: annotations: "helm.sh/hook": no-such-hook `, - }, { + }, + { name: []string{"fourth"}, path: "four", kind: []string{"Pod"}, @@ -84,7 +86,8 @@ metadata: name: fourth annotations: nothing: here`, - }, { + }, + { name: []string{"fifth"}, path: "five", kind: []string{"ReplicaSet"}, @@ -96,14 +99,16 @@ metadata: annotations: "helm.sh/hook": post-delete, post-install `, - }, { + }, + { // Regression test: files with an underscore in the base name should be skipped. name: []string{"sixth"}, path: "six/_six", kind: []string{"ReplicaSet"}, hooks: map[string][]release.HookEvent{"sixth": nil}, manifest: `invalid manifest`, // This will fail if partial is not skipped. - }, { + }, + { // Regression test: files with no content should be skipped. name: []string{"seventh"}, path: "seven", diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 09fc7de8a..9b46065a8 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -424,7 +424,6 @@ func TestIndexAdd(t *testing.T) { baseURL string digest string }{ - {&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"}, {&chart.Metadata{APIVersion: "v2", Name: "alpine", Version: "0.1.0"}, "/home/charts/alpine-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"}, {&chart.Metadata{APIVersion: "v2", Name: "deis", Version: "0.1.0"}, "/home/charts/deis-0.1.0.tgz", "http://example.com/charts/", "sha256:1234567890"}, @@ -536,6 +535,7 @@ entries: home: https://github.com/something/else digest: "sha256:1234567890abcdef" ` + var indexWithDuplicatesInLastChartDeps = ` apiVersion: v1 entries: diff --git a/pkg/repo/v1/repo_test.go b/pkg/repo/v1/repo_test.go index f7f5df9be..2fe780ce3 100644 --- a/pkg/repo/v1/repo_test.go +++ b/pkg/repo/v1/repo_test.go @@ -137,15 +137,17 @@ func TestUpdateRepository(t *testing.T) { }, ) newRepoName := "sample" - sampleRepository.Update(&Entry{Name: newRepoName, - URL: "https://example.com/sample", + sampleRepository.Update(&Entry{ + Name: newRepoName, + URL: "https://example.com/sample", }) assert.Truef(t, sampleRepository.Has(newRepoName), "expected repository %s not found", newRepoName) repoCount := len(sampleRepository.Repositories) - sampleRepository.Update(&Entry{Name: newRepoName, - URL: "https://example.com/sample", + sampleRepository.Update(&Entry{ + Name: newRepoName, + URL: "https://example.com/sample", }) assert.Lenf(t, sampleRepository.Repositories, repoCount, "invalid number of repositories found %d, expected number of repositories %d", len(sampleRepository.Repositories), repoCount) diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index 34f01be79..81c2c5149 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -23,7 +23,7 @@ import ( ) func TestLabelsMatch(t *testing.T) { - var tests = []struct { + tests := []struct { desc string set1 labels set2 labels diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index c0eff3cf9..745b12345 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -34,7 +34,7 @@ func TestMemoryName(t *testing.T) { } func TestMemoryCreate(t *testing.T) { - var tests = []struct { + tests := []struct { desc string rls *rspb.Release err bool @@ -76,7 +76,7 @@ func TestMemoryCreate(t *testing.T) { } func TestMemoryGet(t *testing.T) { - var tests = []struct { + tests := []struct { desc string key string namespace string @@ -133,7 +133,7 @@ func TestMemoryList(t *testing.T) { } func TestMemoryQuery(t *testing.T) { - var tests = []struct { + tests := []struct { desc string xlen int namespace string @@ -164,7 +164,7 @@ func TestMemoryQuery(t *testing.T) { } func TestMemoryUpdate(t *testing.T) { - var tests = []struct { + tests := []struct { desc string key string rls *rspb.Release @@ -215,7 +215,7 @@ func TestMemoryUpdate(t *testing.T) { } func TestMemoryDelete(t *testing.T) { - var tests = []struct { + tests := []struct { desc string key string namespace string diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 22d54e6cc..049536971 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -31,7 +31,7 @@ func TestRecordsAdd(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - var tests = []struct { + tests := []struct { desc string key string ok bool @@ -62,7 +62,7 @@ func TestRecordsAdd(t *testing.T) { } func TestRecordsRemove(t *testing.T) { - var tests = []struct { + tests := []struct { desc string key string ok bool @@ -112,7 +112,7 @@ func TestRecordsGet(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - var tests = []struct { + tests := []struct { desc string key string rec *record @@ -141,7 +141,7 @@ func TestRecordsIndex(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - var tests = []struct { + tests := []struct { desc string key string sort int @@ -170,7 +170,7 @@ func TestRecordsExists(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - var tests = []struct { + tests := []struct { desc string key string ok bool @@ -199,7 +199,7 @@ func TestRecordsReplace(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - var tests = []struct { + tests := []struct { desc string key string rec *record diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index 85e6cbd3f..db076da98 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -53,8 +53,10 @@ const postgreSQLDialect = "postgres" // SQLDriverName is the string name of this driver. const SQLDriverName = "SQL" -const sqlReleaseTableName = "releases_v1" -const sqlCustomLabelsTableName = "custom_labels_v1" +const ( + sqlReleaseTableName = "releases_v1" + sqlCustomLabelsTableName = "custom_labels_v1" +) const ( sqlReleaseTableKeyColumn = "key" @@ -359,7 +361,7 @@ func (s *SQL) List(filter func(release.Releaser) bool) ([]release.Releaser, erro return nil, err } - var records = []SQLReleaseWrapper{} + records := []SQLReleaseWrapper{} if err := s.db.Select(&records, query, args...); err != nil { s.Logger().Debug("failed to list", slog.Any("error", err)) return nil, err @@ -424,7 +426,7 @@ func (s *SQL) Query(labels map[string]string) ([]release.Releaser, error) { return nil, err } - var records = []SQLReleaseWrapper{} + records := []SQLReleaseWrapper{} if err := s.db.Select(&records, query, args...); err != nil { s.Logger().Debug("failed to query with labels", slog.Any("error", err)) return nil, err @@ -556,7 +558,6 @@ func (s *SQL) Create(key string, rel release.Releaser) error { k, v, ).ToSql() - if err != nil { defer transaction.Rollback() s.Logger().Debug("failed to build insert query", slog.Any("error", err)) @@ -603,7 +604,6 @@ func (s *SQL) Update(key string, rel release.Releaser) error { Where(sq.Eq{sqlReleaseTableKeyColumn: key}). Where(sq.Eq{sqlReleaseTableNamespaceColumn: namespace}). ToSql() - if err != nil { s.Logger().Debug("failed to build update query", slog.Any("error", err)) return err @@ -681,7 +681,6 @@ func (s *SQL) Delete(key string) (release.Releaser, error) { Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key}). Where(sq.Eq{sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}). ToSql() - if err != nil { s.Logger().Debug("failed to build delete Labels query", slog.Any("error", err)) return nil, err @@ -695,14 +694,16 @@ func (s *SQL) getReleaseCustomLabels(key string, _ string) (map[string]string, e query, args, err := s.statementBuilder. Select(sqlCustomLabelsTableKeyColumn, sqlCustomLabelsTableValueColumn). From(sqlCustomLabelsTableName). - Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key, - sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}). + Where(sq.Eq{ + sqlCustomLabelsTableReleaseKeyColumn: key, + sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace, + }). ToSql() if err != nil { return nil, err } - var labelsList = []SQLReleaseCustomLabelWrapper{} + labelsList := []SQLReleaseCustomLabelWrapper{} if err := s.db.Select(&labelsList, query, args...); err != nil { return nil, err } diff --git a/pkg/storage/driver/util_test.go b/pkg/storage/driver/util_test.go index 5dda3cd1f..f84f6a67a 100644 --- a/pkg/storage/driver/util_test.go +++ b/pkg/storage/driver/util_test.go @@ -38,7 +38,7 @@ func TestIsSystemLabel(t *testing.T) { } func TestFilterSystemLabels(t *testing.T) { - var tests = [][2]map[string]string{ + tests := [][2]map[string]string{ {nil, map[string]string{}}, {map[string]string{}, map[string]string{}}, {map[string]string{ @@ -73,7 +73,7 @@ func TestFilterSystemLabels(t *testing.T) { } func TestContainsSystemLabels(t *testing.T) { - var tests = []struct { + tests := []struct { input map[string]string output bool }{ diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 58cb56776..ae8513cca 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -137,7 +137,7 @@ func TestStorageList(t *testing.T) { require.NoError(t, storage.Create(rls6), "Storing release 'rls6'") } - var listTests = []struct { + listTests := []struct { Description string NumExpected int ListFunc func() ([]release.Releaser, error) @@ -263,24 +263,31 @@ type MaxHistoryMockDriver struct { func NewMaxHistoryMockDriver(d driver.Driver) *MaxHistoryMockDriver { return &MaxHistoryMockDriver{Driver: d} } + func (d *MaxHistoryMockDriver) Create(key string, rls release.Releaser) error { return d.Driver.Create(key, rls) } + func (d *MaxHistoryMockDriver) Update(key string, rls release.Releaser) error { return d.Driver.Update(key, rls) } + func (d *MaxHistoryMockDriver) Delete(_ string) (release.Releaser, error) { return nil, errMaxHistoryMockDriverSomethingHappened } + func (d *MaxHistoryMockDriver) Get(key string) (release.Releaser, error) { return d.Driver.Get(key) } + func (d *MaxHistoryMockDriver) List(filter func(release.Releaser) bool) ([]release.Releaser, error) { return d.Driver.List(filter) } + func (d *MaxHistoryMockDriver) Query(labels map[string]string) ([]release.Releaser, error) { return d.Driver.Query(labels) } + func (d *MaxHistoryMockDriver) Name() string { return d.Driver.Name() } diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index 94e0c6050..74ab775af 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -316,7 +316,8 @@ func TestParseLiteralInto(t *testing.T) { "outer": map[string]any{ "inner1": "value1,outer.inner3=value3,outer.inner4=4", "inner2": "value2", - }}, + }, + }, err: false, }, { diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index c6c866711..73fc3f206 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -439,7 +439,8 @@ func TestParseInto(t *testing.T) { "inner2": "value2", "inner3": "value3", "inner4": 4, - }}, + }, + }, err: false, }, { From bc0114c70841e2a05c95e53e20358fb761dbfb2e Mon Sep 17 00:00:00 2001 From: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:55:05 -0500 Subject: [PATCH 151/161] fix(scripts): clarify cache-busting behavior Signed-off-by: Solomon Wakhungu <65043605+1solomonwakhungu@users.noreply.github.com> --- scripts/get-helm-3 | 3 ++- scripts/get-helm-4 | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 117ae3e03..a73b3da2a 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -114,12 +114,13 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL + # Cache behavior is provider-specific, so this mitigation is best effort. # The current CDN does not revalidate on the request no-cache directive, # so use a unique query while retaining no-cache for compliant intermediaries. local latest_release_url="https://get.helm.sh/helm3-latest-version?ts=$(date +%s)" local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then - latest_release_response=$( curl -L --silent --show-error --fail -H "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) + latest_release_response=$( curl -L --silent --show-error --fail --header "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) elif [ "${HAS_WGET}" == "true" ]; then latest_release_response=$( wget "$latest_release_url" --header="Cache-Control: no-cache" -q -O - 2>&1 || true ) fi diff --git a/scripts/get-helm-4 b/scripts/get-helm-4 index 0ff312a7f..3d232cca9 100644 --- a/scripts/get-helm-4 +++ b/scripts/get-helm-4 @@ -114,12 +114,13 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL + # Cache behavior is provider-specific, so this mitigation is best effort. # The current CDN does not revalidate on the request no-cache directive, # so use a unique query while retaining no-cache for compliant intermediaries. local latest_release_url="https://get.helm.sh/helm4-latest-version?ts=$(date +%s)" local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then - latest_release_response=$( curl -L --silent --show-error --fail -H "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) + latest_release_response=$( curl -L --silent --show-error --fail --header "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true ) elif [ "${HAS_WGET}" == "true" ]; then latest_release_response=$( wget "$latest_release_url" --header="Cache-Control: no-cache" -q -O - 2>&1 || true ) fi From ce27485634fcbd54be8fc8d99a5e4799456420c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:33:45 +0000 Subject: [PATCH 152/161] chore(deps): bump go.yaml.in/yaml/v3 from 3.0.4 to 3.0.5 Bumps [go.yaml.in/yaml/v3](https://github.com/yaml/go-yaml) from 3.0.4 to 3.0.5. - [Commits](https://github.com/yaml/go-yaml/compare/v3.0.4...v3.0.5) --- updated-dependencies: - dependency-name: go.yaml.in/yaml/v3 dependency-version: 3.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6b9878bb2..13434162f 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 github.com/tetratelabs/wazero v1.12.0 - go.yaml.in/yaml/v3 v3.0.4 + go.yaml.in/yaml/v3 v3.0.5 golang.org/x/crypto v0.54.0 golang.org/x/term v0.45.0 golang.org/x/text v0.40.0 diff --git a/go.sum b/go.sum index e5933d99a..9afe18b88 100644 --- a/go.sum +++ b/go.sum @@ -376,8 +376,9 @@ go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= From ac1c68746f72e5bbbe5b7e5a052629aab7e5ab61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:39:05 -0600 Subject: [PATCH 153/161] chore(deps): bump actions/stale in the github-actions group (#32487) Bumps the github-actions group with 1 update: [actions/stale](https://github.com/actions/stale). Updates `actions/stale` from 10.4.0 to 11.0.0 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/1e223db275d687790206a7acac4d1a11bd6fe629...4391f3da665fdf50b6810c1a66712fb9ba21aa93) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 11.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 678952b03..e95a4b8c3 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -12,7 +12,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0 + - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' From a8ab76e86f11e2ece5a3d0262313140e21db249b Mon Sep 17 00:00:00 2001 From: Nikolaus Schuetz Date: Tue, 28 Jul 2026 17:59:38 -0700 Subject: [PATCH 154/161] test(action): poll for the interrupted install goroutine instead of a zero-margin sleep (#32328) TestInstallRelease_Wait_Interrupted and TestInstallRelease_RollbackOnFailure_Interrupted assert that the detached installation goroutine has exited by sleeping a fixed 10s -- exactly the FailingKubeClient WaitDuration the goroutine blocks on. Sleeping the same duration the goroutine takes is a zero-margin race: if the goroutine finishes a hair after the fixed sleep elapses (scheduler jitter under load), getGoroutineCount() has not decremented yet and the assertion flakes. Replace the fixed sleep + point-in-time assert with is.Eventually polling getGoroutineCount() (30s ceiling, 10ms tick). It returns as soon as the goroutine has actually finished and no longer races the exact wait duration. Test-only; no change to install behavior. Signed-off-by: Nikolaus Schuetz --- pkg/action/install_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 80f3bd724..2d83abe27 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -653,8 +653,10 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { req.ErrorContains(err, "context canceled") is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background - time.Sleep(10 * time.Second) // wait for goroutine to finish - is.Equal(goroutines, instAction.getGoroutineCount()) + // Poll until the background installation goroutine has finished. + is.Eventually(func() bool { + return instAction.getGoroutineCount() == goroutines + }, 30*time.Second, 10*time.Millisecond) } func TestInstallRelease_WaitForJobs(t *testing.T) { @@ -754,8 +756,10 @@ func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { req.Error(err) is.Equal(err, driver.ErrReleaseNotFound) is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background - time.Sleep(10 * time.Second) // wait for goroutine to finish - is.Equal(goroutines, instAction.getGoroutineCount()) + // Poll until the background installation goroutine has finished. + is.Eventually(func() bool { + return instAction.getGoroutineCount() == goroutines + }, 30*time.Second, 10*time.Millisecond) } func TestNameTemplate(t *testing.T) { From ae877c8bfb943d2cc1aa10b34f0c4fada55e6f56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:54:38 -0600 Subject: [PATCH 155/161] chore(deps): bump the github-actions group with 4 updates (#32508) Bumps the github-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38) Updates `github/codeql-action/autobuild` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38) Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38) Updates `github/codeql-action/upload-sarif` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecards.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d8c1a9d12..1c541c2bf 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 + uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 + uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 + uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 6c142b511..d631fa5ea 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: sarif_file: results.sarif From 47eb219a71bac4638a9b9db916a5d8c415c553bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 22:06:50 +0000 Subject: [PATCH 156/161] chore(deps): bump the github-actions group with 4 updates Bumps the github-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/autobuild` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/analyze` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) Updates `github/codeql-action/upload-sarif` from 4.37.4 to 4.37.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...d1ba80a13dd99fba24a470575428917156a28b43) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecards.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1c541c2bf..775299964 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 + uses: github/codeql-action/init@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 + uses: github/codeql-action/autobuild@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # pinv4.37.4 + uses: github/codeql-action/analyze@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d631fa5ea..926b0c3f6 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 + uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 with: sarif_file: results.sarif From f8a308cd470bc1f087b3f4915ba775af18c5ffab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 05:31:22 -0600 Subject: [PATCH 157/161] chore(deps): bump github.com/santhosh-tekuri/jsonschema/v6 (#32514) Bumps [github.com/santhosh-tekuri/jsonschema/v6](https://github.com/santhosh-tekuri/jsonschema) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/santhosh-tekuri/jsonschema/releases) - [Commits](https://github.com/santhosh-tekuri/jsonschema/compare/v6.0.2...v6.0.3) --- updated-dependencies: - dependency-name: github.com/santhosh-tekuri/jsonschema/v6 dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 13434162f..3843e17aa 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 github.com/rubenv/sql-migrate v1.8.1 - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 9afe18b88..46bc13845 100644 --- a/go.sum +++ b/go.sum @@ -282,8 +282,8 @@ github.com/rubenv/sql-migrate v1.8.1 h1:EPNwCvjAowHI3TnZ+4fQu3a915OpnQoPAjTXCGOy github.com/rubenv/sql-migrate v1.8.1/go.mod h1:BTIKBORjzyxZDS6dzoiw6eAFYJ1iNlGAtjn4LGeVjS8= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= From a0c2f6dade5180fdb08bcc5debef56357cd586ab Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Fri, 7 Aug 2026 08:12:24 -0600 Subject: [PATCH 158/161] fix: bump go.opentelemetry.io/otel to v1.44.0 for GO-2026-5158 (#32521) * fix: bump go.opentelemetry.io/otel to v1.44.0 for GO-2026-5158 govulncheck on main flags GO-2026-5158 in go.opentelemetry.io/otel@v1.43.0 (fixed in v1.44.0). Bump the transitive otel dependency to clear the vulnerability. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Terry Howe * fix: bump otel/sdk and otel/sdk/metric to v1.44.0 for version parity Keep the lockstep-versioned OpenTelemetry core and SDK modules aligned at v1.44.0 to avoid version skew. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Terry Howe --------- Signed-off-by: Terry Howe Co-authored-by: Claude Opus 4.8 (1M context) --- go.mod | 10 +++++----- go.sum | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 3843e17aa..6203377b7 100644 --- a/go.mod +++ b/go.mod @@ -138,7 +138,7 @@ require ( go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect @@ -151,11 +151,11 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 // indirect go.opentelemetry.io/otel/log v0.19.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect - go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/mod v0.37.0 // indirect diff --git a/go.sum b/go.sum index 46bc13845..1b7a58218 100644 --- a/go.sum +++ b/go.sum @@ -328,8 +328,8 @@ go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9a go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= @@ -354,18 +354,20 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1J go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= From f3d68cdbea3076a0283cbd1e3ec44a409ad48a43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:53:05 -0600 Subject: [PATCH 159/161] chore(deps): bump the github-actions group with 4 updates (#32523) Bumps the github-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/autobuild` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/analyze` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) Updates `github/codeql-action/upload-sarif` from 4.37.5 to 4.37.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/d1ba80a13dd99fba24a470575428917156a28b43...5595ccaf912efad79be6eef63a5619ff05969be3) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/autobuild dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/scorecards.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 775299964..5e392cc2c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 + uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # pinv4.37.6 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 + uses: github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # pinv4.37.6 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@d1ba80a13dd99fba24a470575428917156a28b43 # pinv4.37.5 + uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # pinv4.37.6 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 926b0c3f6..553a6b3da 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5 + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: sarif_file: results.sarif From edb94f897d1e0ec3335fb7268f07e0fd2666fbb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:43:12 -0600 Subject: [PATCH 160/161] chore(deps): bump golang.org/x/text from 0.40.0 to 0.41.0 (#32543) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.40.0 to 0.41.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.40.0...v0.41.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-version: 0.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6203377b7..a2f06e39f 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( go.yaml.in/yaml/v3 v3.0.5 golang.org/x/crypto v0.54.0 golang.org/x/term v0.45.0 - golang.org/x/text v0.40.0 + golang.org/x/text v0.41.0 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.36.3 k8s.io/apiextensions-apiserver v0.36.3 @@ -158,13 +158,13 @@ require ( go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/mod v0.37.0 // indirect - golang.org/x/net v0.56.0 // indirect + golang.org/x/mod v0.38.0 // indirect + golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect - golang.org/x/tools v0.47.0 // indirect + golang.org/x/tools v0.48.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/grpc v1.82.1 // indirect diff --git a/go.sum b/go.sum index 1b7a58218..75ac7bb0e 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -405,8 +405,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -453,8 +453,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -463,8 +463,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= From 2a29f1770b62844b27197d2507377361d45ad7c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:50:55 -0600 Subject: [PATCH 161/161] chore(deps): bump golang.org/x/crypto from 0.54.0 to 0.55.0 (#32545) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.54.0 to 0.55.0. - [Commits](https://github.com/golang/crypto/compare/v0.54.0...v0.55.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.55.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a2f06e39f..4c0468708 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tetratelabs/wazero v1.12.0 go.yaml.in/yaml/v3 v3.0.5 - golang.org/x/crypto v0.54.0 + golang.org/x/crypto v0.55.0 golang.org/x/term v0.45.0 golang.org/x/text v0.41.0 gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 75ac7bb0e..35d9e4465 100644 --- a/go.sum +++ b/go.sum @@ -387,8 +387,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=