From 268593bf2e9769ef4b75328b33dfb4195e6e9e5a Mon Sep 17 00:00:00 2001 From: Manuel Alonso <434575+manute@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:21:02 +0100 Subject: [PATCH 1/7] fix(action): crd resources can be empty Signed-off-by: Manuel Alonso <434575+manute@users.noreply.github.com> --- pkg/action/install.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/action/install.go b/pkg/action/install.go index 2f5910284..b0c28132a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -186,6 +186,10 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err) } + if res == nil { + return fmt.Errorf("failed to install CRD %s: resources are empty", obj.Name) + } + // Send them to Kube if _, err := i.cfg.KubeClient.Create( res, From 52235cc0bf7d0c8faf17c7dc8cddd77f93434aea Mon Sep 17 00:00:00 2001 From: Manuel Alonso <434575+manute@users.noreply.github.com> Date: Wed, 26 Nov 2025 18:33:20 +0100 Subject: [PATCH 2/7] fix(install): check lenght and file nil, add tests Signed-off-by: Manuel Alonso <434575+manute@users.noreply.github.com> --- pkg/action/install.go | 6 +++++- pkg/action/install_test.go | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index b0c28132a..b2e8f8bf4 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -180,13 +180,17 @@ func (i *Install) installCRDs(crds []chart.CRD) error { // We do these one file at a time in the order they were read. totalItems := []*resource.Info{} for _, obj := range crds { + if obj.File == nil { + return fmt.Errorf("failed to install CRD %s: file is empty", obj.Name) + } + // Read in the resources res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false) if err != nil { return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err) } - if res == nil { + if len(res) == 0 { return fmt.Errorf("failed to install CRD %s: resources are empty", obj.Name) } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 9f04f40d4..a9a33881a 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -45,6 +45,7 @@ import ( "helm.sh/helm/v4/internal/test" "helm.sh/helm/v4/pkg/chart/common" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/kube" kubefake "helm.sh/helm/v4/pkg/kube/fake" rcommon "helm.sh/helm/v4/pkg/release/common" @@ -1068,3 +1069,42 @@ func TestInstallRun_UnreachableKubeClient(t *testing.T) { assert.Nil(t, res) assert.ErrorContains(t, err, "connection refused") } + +func TestInstallCRDs_CheckNilErrors(t *testing.T) { + tests := []struct { + name string + input []chart.CRD + }{ + { + name: "only one crd with file nil", + input: []chart.CRD{ + {Name: "one", File: nil}, + }, + }, + { + name: "only one crd with its file data nil", + input: []chart.CRD{ + {Name: "one", File: &common.File{Name: "crds/foo.yaml", Data: nil}}, + }, + }, + { + name: "at least a crd with its file data nil", + input: []chart.CRD{ + {Name: "one", File: &common.File{Name: "crds/foo.yaml", Data: []byte("data")}}, + {Name: "two", File: &common.File{Name: "crds/foo.yaml", Data: nil}}, + {Name: "three", File: &common.File{Name: "crds/foo.yaml", Data: []byte("data")}}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + instAction := installAction(t) + + err := instAction.installCRDs(tt.input) + if err == nil { + t.Errorf("got error expected nil") + } + }) + } +} From 0357e8d0f7eab074252ca49e1ca3aded834a001d Mon Sep 17 00:00:00 2001 From: Manuel Alonso <434575+manute@users.noreply.github.com> Date: Mon, 22 Dec 2025 19:15:16 +0100 Subject: [PATCH 3/7] fix(test): no check empty resources Signed-off-by: Manuel Alonso <434575+manute@users.noreply.github.com> --- pkg/action/install.go | 4 ---- pkg/action/install_test.go | 16 ++++++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index b2e8f8bf4..57839b289 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -190,10 +190,6 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err) } - if len(res) == 0 { - return fmt.Errorf("failed to install CRD %s: resources are empty", obj.Name) - } - // Send them to Kube if _, err := i.cfg.KubeClient.Create( res, diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index a9a33881a..38ea556f5 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1072,28 +1072,32 @@ func TestInstallRun_UnreachableKubeClient(t *testing.T) { func TestInstallCRDs_CheckNilErrors(t *testing.T) { tests := []struct { - name string - input []chart.CRD + name string + input []chart.CRD + expectedErr bool }{ { name: "only one crd with file nil", input: []chart.CRD{ {Name: "one", File: nil}, }, + expectedErr: true, }, { name: "only one crd with its file data nil", input: []chart.CRD{ {Name: "one", File: &common.File{Name: "crds/foo.yaml", Data: nil}}, }, + expectedErr: false, }, { name: "at least a crd with its file data nil", input: []chart.CRD{ {Name: "one", File: &common.File{Name: "crds/foo.yaml", Data: []byte("data")}}, - {Name: "two", File: &common.File{Name: "crds/foo.yaml", Data: nil}}, - {Name: "three", File: &common.File{Name: "crds/foo.yaml", Data: []byte("data")}}, + {Name: "two", File: &common.File{Name: "crds/foo2.yaml", Data: nil}}, + {Name: "three", File: &common.File{Name: "crds/foo3.yaml", Data: []byte("data")}}, }, + expectedErr: false, }, } @@ -1102,8 +1106,8 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { instAction := installAction(t) err := instAction.installCRDs(tt.input) - if err == nil { - t.Errorf("got error expected nil") + if tt.expectedErr && err == nil { + t.Errorf("got error %v expected nil", err) } }) } From 00f0a48a7dae379c2b6bd0dea43984d42b27a494 Mon Sep 17 00:00:00 2001 From: Manuel Alonso <434575+manute@users.noreply.github.com> Date: Tue, 23 Dec 2025 09:35:14 +0100 Subject: [PATCH 4/7] fix(install): add more tests and check nil file data Signed-off-by: Manuel Alonso <434575+manute@users.noreply.github.com> --- pkg/action/install.go | 8 ++++++++ pkg/action/install_test.go | 12 ++++-------- pkg/cmd/install_test.go | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 57839b289..e832bef0a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -184,12 +184,20 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return fmt.Errorf("failed to install CRD %s: file is empty", obj.Name) } + if obj.File.Data == nil { + return fmt.Errorf("failed to install CRD %s: file data is empty", obj.Name) + } + // Read in the resources res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false) if err != nil { return fmt.Errorf("failed to install CRD %s: %w", obj.Name, err) } + if len(res) == 0 { + return fmt.Errorf("failed to install CRD %s: resources are empty", obj.Name) + } + // Send them to Kube if _, err := i.cfg.KubeClient.Create( res, diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 38ea556f5..11b175df8 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1072,23 +1072,20 @@ func TestInstallRun_UnreachableKubeClient(t *testing.T) { func TestInstallCRDs_CheckNilErrors(t *testing.T) { tests := []struct { - name string - input []chart.CRD - expectedErr bool + name string + input []chart.CRD }{ { name: "only one crd with file nil", input: []chart.CRD{ {Name: "one", File: nil}, }, - expectedErr: true, }, { name: "only one crd with its file data nil", input: []chart.CRD{ {Name: "one", File: &common.File{Name: "crds/foo.yaml", Data: nil}}, }, - expectedErr: false, }, { name: "at least a crd with its file data nil", @@ -1097,7 +1094,6 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { {Name: "two", File: &common.File{Name: "crds/foo2.yaml", Data: nil}}, {Name: "three", File: &common.File{Name: "crds/foo3.yaml", Data: []byte("data")}}, }, - expectedErr: false, }, } @@ -1106,8 +1102,8 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { instAction := installAction(t) err := instAction.installCRDs(tt.input) - if tt.expectedErr && err == nil { - t.Errorf("got error %v expected nil", err) + if err == nil { + t.Errorf("got nil expected err") } }) } diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index f0f12e4f7..5fa3c1340 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -240,7 +240,7 @@ func TestInstall(t *testing.T) { // Install chart with only crds { name: "install chart with only crds", - cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default", + cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default --dry-run", }, // Verify the user/pass works { From 561410ae1d09c2aa289ff8d8cad5b7fa979cd135 Mon Sep 17 00:00:00 2001 From: Manuel Alonso Gonzalez Date: Sat, 10 Jan 2026 09:49:30 +0100 Subject: [PATCH 5/7] fix(test): merge fix correctly Signed-off-by: Manuel Alonso Gonzalez <434575+manute@users.noreply.github.com> Signed-off-by: Manuel Alonso Gonzalez --- pkg/action/install_test.go | 113 +++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 8aa243663..fc8a96319 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1074,6 +1074,119 @@ func TestInstallRun_UnreachableKubeClient(t *testing.T) { assert.ErrorContains(t, err, "connection refused") } +func TestInstallSetRegistryClient(t *testing.T) { + config := actionConfigFixture(t) + instAction := NewInstall(config) + + registryClient := ®istry.Client{} + instAction.SetRegistryClient(registryClient) + + assert.Equal(t, registryClient, instAction.GetRegistryClient()) +} + +func TestInstalLCRDs(t *testing.T) { + config := actionConfigFixture(t) + instAction := NewInstall(config) + + mockFile := common.File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + } + mockChart := buildChart(withFile(mockFile)) + crdsToInstall := mockChart.CRDObjects() + assert.Len(t, crdsToInstall, 1) + assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) + + require.NoError(t, instAction.installCRDs(crdsToInstall)) +} + +func TestInstalLCRDs_KubeClient_BuildError(t *testing.T) { + config := actionConfigFixture(t) + failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} + failingKubeClient.BuildError = errors.New("build error") + config.KubeClient = &failingKubeClient + instAction := NewInstall(config) + + mockFile := common.File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + } + mockChart := buildChart(withFile(mockFile)) + crdsToInstall := mockChart.CRDObjects() + + require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") +} + +func TestInstalLCRDs_KubeClient_CreateError(t *testing.T) { + config := actionConfigFixture(t) + failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} + failingKubeClient.CreateError = errors.New("create error") + config.KubeClient = &failingKubeClient + instAction := NewInstall(config) + + mockFile := common.File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + } + mockChart := buildChart(withFile(mockFile)) + crdsToInstall := mockChart.CRDObjects() + + require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") +} + +func TestInstalLCRDs_AlreadyExist(t *testing.T) { + config := actionConfigFixture(t) + failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} + mockError := &apierrors.StatusError{ErrStatus: metav1.Status{ + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonAlreadyExists, + }} + failingKubeClient.CreateError = mockError + config.KubeClient = &failingKubeClient + instAction := NewInstall(config) + + mockFile := common.File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + } + mockChart := buildChart(withFile(mockFile)) + crdsToInstall := mockChart.CRDObjects() + + assert.Nil(t, instAction.installCRDs(crdsToInstall)) +} + +func TestInstalLCRDs_WaiterError(t *testing.T) { + config := actionConfigFixture(t) + failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} + failingKubeClient.WaitError = errors.New("wait error") + failingKubeClient.BuildDummy = true + config.KubeClient = &failingKubeClient + instAction := NewInstall(config) + + mockFile := common.File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + } + mockChart := buildChart(withFile(mockFile)) + crdsToInstall := mockChart.CRDObjects() + + require.Error(t, instAction.installCRDs(crdsToInstall), "wait error") +} + +func TestCheckDependencies(t *testing.T) { + dependency := chart.Dependency{Name: "hello"} + mockChart := buildChart(withDependency()) + + assert.Nil(t, CheckDependencies(mockChart, []ci.Dependency{&dependency})) +} + +func TestCheckDependencies_MissingDependency(t *testing.T) { + dependency := chart.Dependency{Name: "missing"} + mockChart := buildChart(withDependency()) + + assert.ErrorContains(t, CheckDependencies(mockChart, []ci.Dependency{&dependency}), "missing in charts") +} + func TestInstallCRDs_CheckNilErrors(t *testing.T) { tests := []struct { name string From 0f949a92c149cf11e5bb19caf4d19d05567be6eb Mon Sep 17 00:00:00 2001 From: Manuel Alonso Date: Sun, 11 Jan 2026 21:08:31 +0100 Subject: [PATCH 6/7] fix(test): fix tests and check nil for restclient Signed-off-by: Manuel Alonso --- pkg/action/install.go | 48 ++++++++++++++++++++------------------ pkg/action/install_test.go | 15 ++++++------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index f1677c297..b84e9eaf9 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -222,32 +222,34 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return err } - // If we have already gathered the capabilities, we need to invalidate - // the cache so that the new CRDs are recognized. This should only be - // the case when an action configuration is reused for multiple actions, - // as otherwise it is later loaded by ourselves when getCapabilities - // is called later on in the installation process. - if i.cfg.Capabilities != nil { - discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() - if err != nil { - return err - } + if i.cfg.RESTClientGetter != nil { + // If we have already gathered the capabilities, we need to invalidate + // the cache so that the new CRDs are recognized. This should only be + // the case when an action configuration is reused for multiple actions, + // as otherwise it is later loaded by ourselves when getCapabilities + // is called later on in the installation process. + if i.cfg.Capabilities != nil { + discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() + if err != nil { + return err + } - i.cfg.Logger().Debug("clearing discovery cache") - discoveryClient.Invalidate() + i.cfg.Logger().Debug("clearing discovery cache") + discoveryClient.Invalidate() - _, _ = discoveryClient.ServerGroups() - } + _, _ = discoveryClient.ServerGroups() + } - // Invalidate the REST mapper, since it will not have the new CRDs - // present. - restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() - if err != nil { - return err - } - if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { - i.cfg.Logger().Debug("clearing REST mapper cache") - resettable.Reset() + // Invalidate the REST mapper, since it will not have the new CRDs + // present. + restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() + if err != nil { + return err + } + if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { + i.cfg.Logger().Debug("clearing REST mapper cache") + resettable.Reset() + } } } return nil diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index fc8a96319..76c35b628 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1084,8 +1084,8 @@ func TestInstallSetRegistryClient(t *testing.T) { assert.Equal(t, registryClient, instAction.GetRegistryClient()) } -func TestInstalLCRDs(t *testing.T) { - config := actionConfigFixture(t) +func TestInstallCRDs(t *testing.T) { + config := actionConfigFixtureWithDummyResources(t, createDummyResourceList(false)) instAction := NewInstall(config) mockFile := common.File{ @@ -1100,7 +1100,7 @@ func TestInstalLCRDs(t *testing.T) { require.NoError(t, instAction.installCRDs(crdsToInstall)) } -func TestInstalLCRDs_KubeClient_BuildError(t *testing.T) { +func TestInstallCRDs_KubeClient_BuildError(t *testing.T) { config := actionConfigFixture(t) failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} failingKubeClient.BuildError = errors.New("build error") @@ -1117,7 +1117,7 @@ func TestInstalLCRDs_KubeClient_BuildError(t *testing.T) { require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") } -func TestInstalLCRDs_KubeClient_CreateError(t *testing.T) { +func TestInstallCRDs_KubeClient_CreateError(t *testing.T) { config := actionConfigFixture(t) failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} failingKubeClient.CreateError = errors.New("create error") @@ -1134,7 +1134,7 @@ func TestInstalLCRDs_KubeClient_CreateError(t *testing.T) { require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") } -func TestInstalLCRDs_AlreadyExist(t *testing.T) { +func TestInstallCRDs_AlreadyExist(t *testing.T) { config := actionConfigFixture(t) failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} mockError := &apierrors.StatusError{ErrStatus: metav1.Status{ @@ -1149,13 +1149,14 @@ func TestInstalLCRDs_AlreadyExist(t *testing.T) { Name: "crds/foo.yaml", Data: []byte("hello"), } + mockChart := buildChart(withFile(mockFile)) crdsToInstall := mockChart.CRDObjects() - assert.Nil(t, instAction.installCRDs(crdsToInstall)) + require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") } -func TestInstalLCRDs_WaiterError(t *testing.T) { +func TestInstallCRDs_WaiterError(t *testing.T) { config := actionConfigFixture(t) failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} failingKubeClient.WaitError = errors.New("wait error") From 6501ef490a45e9b7edfed1432702532c5b11c6d2 Mon Sep 17 00:00:00 2001 From: Manuel Alonso Date: Tue, 13 Jan 2026 19:21:16 +0100 Subject: [PATCH 7/7] chore(refactor): better testing and functionality for installing crd Signed-off-by: Manuel Alonso --- pkg/action/install.go | 48 ++++++++++++++++++-------------------- pkg/action/install_test.go | 40 +++++++++++-------------------- 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index b84e9eaf9..f1677c297 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -222,34 +222,32 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return err } - if i.cfg.RESTClientGetter != nil { - // If we have already gathered the capabilities, we need to invalidate - // the cache so that the new CRDs are recognized. This should only be - // the case when an action configuration is reused for multiple actions, - // as otherwise it is later loaded by ourselves when getCapabilities - // is called later on in the installation process. - if i.cfg.Capabilities != nil { - discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() - if err != nil { - return err - } - - i.cfg.Logger().Debug("clearing discovery cache") - discoveryClient.Invalidate() - - _, _ = discoveryClient.ServerGroups() - } - - // Invalidate the REST mapper, since it will not have the new CRDs - // present. - restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() + // If we have already gathered the capabilities, we need to invalidate + // the cache so that the new CRDs are recognized. This should only be + // the case when an action configuration is reused for multiple actions, + // as otherwise it is later loaded by ourselves when getCapabilities + // is called later on in the installation process. + if i.cfg.Capabilities != nil { + discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() if err != nil { return err } - if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { - i.cfg.Logger().Debug("clearing REST mapper cache") - resettable.Reset() - } + + i.cfg.Logger().Debug("clearing discovery cache") + discoveryClient.Invalidate() + + _, _ = discoveryClient.ServerGroups() + } + + // Invalidate the REST mapper, since it will not have the new CRDs + // present. + restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() + if err != nil { + return err + } + if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { + i.cfg.Logger().Debug("clearing REST mapper cache") + resettable.Reset() } } return nil diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 76c35b628..003a29528 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -35,7 +35,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kuberuntime "k8s.io/apimachinery/pkg/runtime" @@ -45,6 +44,7 @@ import ( "k8s.io/client-go/rest/fake" ci "helm.sh/helm/v4/pkg/chart" + "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/internal/test" "helm.sh/helm/v4/pkg/chart/common" @@ -1086,6 +1086,8 @@ func TestInstallSetRegistryClient(t *testing.T) { func TestInstallCRDs(t *testing.T) { config := actionConfigFixtureWithDummyResources(t, createDummyResourceList(false)) + config.RESTClientGetter = cli.New().RESTClientGetter() + instAction := NewInstall(config) mockFile := common.File{ @@ -1094,10 +1096,18 @@ func TestInstallCRDs(t *testing.T) { } mockChart := buildChart(withFile(mockFile)) crdsToInstall := mockChart.CRDObjects() - assert.Len(t, crdsToInstall, 1) - assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) - require.NoError(t, instAction.installCRDs(crdsToInstall)) + t.Run("fresh installation", func(t *testing.T) { + assert.Len(t, crdsToInstall, 1) + assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) + require.NoError(t, instAction.installCRDs(crdsToInstall)) + }) + + t.Run("already exist", func(t *testing.T) { + assert.Len(t, crdsToInstall, 1) + assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) + require.NoError(t, instAction.installCRDs(crdsToInstall)) + }) } func TestInstallCRDs_KubeClient_BuildError(t *testing.T) { @@ -1134,28 +1144,6 @@ func TestInstallCRDs_KubeClient_CreateError(t *testing.T) { require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") } -func TestInstallCRDs_AlreadyExist(t *testing.T) { - config := actionConfigFixture(t) - failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil} - mockError := &apierrors.StatusError{ErrStatus: metav1.Status{ - Status: metav1.StatusFailure, - Reason: metav1.StatusReasonAlreadyExists, - }} - failingKubeClient.CreateError = mockError - config.KubeClient = &failingKubeClient - instAction := NewInstall(config) - - mockFile := common.File{ - Name: "crds/foo.yaml", - Data: []byte("hello"), - } - - mockChart := buildChart(withFile(mockFile)) - crdsToInstall := mockChart.CRDObjects() - - require.Error(t, instAction.installCRDs(crdsToInstall), "failed to install CRD") -} - func TestInstallCRDs_WaiterError(t *testing.T) { config := actionConfigFixture(t) failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, DummyResources: nil}