Merge branch 'helm:main' into main

pull/31615/head
MrJack 2 months ago committed by GitHub
commit 9bc0b9a62c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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:
- "*"

@ -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@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@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1
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@7188fc363630916deb702c7fdcf4e481b751f97a # pinv4.37.1
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3

@ -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

@ -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

@ -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=

@ -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
},
}

@ -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"))

@ -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)

@ -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()

@ -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")

@ -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")
})
}
}

@ -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) {

@ -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)
}
})
}

@ -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)

@ -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)")

@ -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")

@ -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) {

@ -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)
})
}
}

@ -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"]

@ -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")
}

@ -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)
}
}

@ -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)
}

@ -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)
},
},
}

@ -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)
}
})
}

@ -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)
}

@ -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)
}
}
}

@ -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 '{'")
}
}

@ -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)
})
}

@ -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)

@ -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")
}

@ -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)
}
}

@ -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())
}

@ -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")
}

@ -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)
}
}

@ -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 <CHARTNAME> 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("<CHARTNAME>")) {
t.Errorf("File %s contains <CHARTNAME>", f)
}
require.NoError(t, err, "Unable to read file %s", f)
assert.Falsef(t, bytes.Contains(b, []byte("<CHARTNAME>")), "File %s contains <CHARTNAME>", 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) {

@ -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())
}
}
}

@ -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)
})
}
}

@ -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)

@ -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())
}

@ -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) {

@ -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))
}

@ -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"])

@ -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")

@ -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)
})
}
}

@ -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) {

@ -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")
}

@ -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")
}

@ -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
}

@ -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.) <helm-testing@helm.sh>\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")
}
}

@ -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)
}

@ -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)
}

@ -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 {

@ -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)

@ -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")
}

@ -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:")
}
})
}

@ -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)
}

@ -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")
}

@ -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)
}

@ -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)
})
}
}

@ -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)

@ -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)
}

@ -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

@ -18,13 +18,17 @@ package cmd
import (
"fmt"
"net/http"
"net/http/httptest"
"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 +48,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 +59,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"
@ -193,6 +185,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)
@ -205,22 +255,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 +277,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 +299,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)
}
if !strings.Contains(upgradedRel.Info.Notes, "PARENT NOTES") {
t.Errorf("The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes)
}
require.NoError(t, err)
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 +322,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 +343,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 +366,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 +395,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 +464,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 +492,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 +519,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 +583,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)
})
}
}

@ -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)
}
})
}

@ -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")

@ -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)
}

@ -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))
})
}

@ -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)
}
}

@ -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

@ -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")
}

@ -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) {

@ -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)
})
}
}

@ -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")
}

@ -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)
})
}
}

@ -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)
})
}
}

@ -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)
}
}

@ -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")
}

@ -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)
}

@ -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() {

@ -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) {

@ -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) {

@ -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{}

@ -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")

@ -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")

@ -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)
}

@ -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{

@ -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)
}

@ -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)
}
}

@ -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)
}
}

@ -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 {

Loading…
Cancel
Save