test(action): reuse FailingKubeClient for the CRD wait strategy test

Drop the test-only strategyAwareWaitKubeClient/strategyAwareWaiter fakes
and use kubefake.FailingKubeClient instead. FailingKubeClient now records
the WaitStrategy passed to GetWaiter/GetWaiterWithOptions in
RecordedWaitStrategies, alongside the existing RecordedWaitOptions, so the
test can assert installCRDs() asks for a StatusWatcherStrategy waiter
under HookOnlyStrategy.

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-opus-5-5 (via Claude Code)
pull/32672/head
Pujitha Paladugu 2 days ago
parent 79784204ea
commit ac4e9e937c
No known key found for this signature in database

@ -1182,56 +1182,14 @@ func TestInstallCRDs_WaiterError(t *testing.T) {
require.Error(t, instAction.installCRDs(crdsToInstall), "wait error")
}
// strategyAwareWaitKubeClient is a fake kube.Interface that records which
// WaitStrategy installCRDs() requests a waiter for, and returns a waiter
// that mimics the real hookOnlyWaiter: its Wait() is a no-op under
// HookOnlyStrategy and reports the CRD as not yet established otherwise.
type strategyAwareWaitKubeClient struct {
kubefake.PrintingKubeClient
requestedStrategy kube.WaitStrategy
}
func (k *strategyAwareWaitKubeClient) Build(_ io.Reader, _ bool) (kube.ResourceList, error) {
var resInfo resource.Info
resInfo.Name = "dummyName"
resInfo.Namespace = "dummyNamespace"
var resourceList kube.ResourceList
resourceList.Append(&resInfo)
return resourceList, nil
}
func (k *strategyAwareWaitKubeClient) GetWaiter(ws kube.WaitStrategy) (kube.Waiter, error) {
return k.GetWaiterWithOptions(ws)
}
func (k *strategyAwareWaitKubeClient) GetWaiterWithOptions(ws kube.WaitStrategy, _ ...kube.WaitOption) (kube.Waiter, error) {
k.requestedStrategy = ws
return &strategyAwareWaiter{strategy: ws}, nil
}
type strategyAwareWaiter struct {
kubefake.PrintingKubeWaiter
strategy kube.WaitStrategy
}
func (w *strategyAwareWaiter) Wait(_ kube.ResourceList, _ time.Duration) error {
if w.strategy == kube.HookOnlyStrategy {
return nil
}
return errors.New("CRD not yet established")
}
// TestInstallCRDs_HookOnlyStrategyStillWaitsForEstablishment guards against
// the regression reported in https://github.com/helm/helm/issues/32671: with
// WaitStrategy set to HookOnlyStrategy, installCRDs() must still wait for
// CRD establishment instead of relying on HookOnlyStrategy's waiter, whose
// Wait() no-ops for general chart resources by design. Before the fix, this
// test failed because installCRDs() requested a HookOnlyStrategy waiter
// (whose no-op Wait() returned nil), swallowing the wait entirely.
// https://github.com/helm/helm/issues/32671: HookOnlyStrategy's waiter does not
// wait on general resources, so installCRDs() must request a
// StatusWatcherStrategy waiter for CRD establishment instead.
func TestInstallCRDs_HookOnlyStrategyStillWaitsForEstablishment(t *testing.T) {
config := actionConfigFixture(t)
fakeClient := &strategyAwareWaitKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}}
config.KubeClient = fakeClient
failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, BuildDummy: true}
config.KubeClient = &failingKubeClient
instAction := NewInstall(config)
instAction.WaitStrategy = kube.HookOnlyStrategy
@ -1242,10 +1200,8 @@ func TestInstallCRDs_HookOnlyStrategyStillWaitsForEstablishment(t *testing.T) {
mockChart := buildChart(withFile(mockFile))
crdsToInstall := mockChart.CRDObjects()
err := instAction.installCRDs(crdsToInstall)
require.Error(t, err, "installCRDs should still wait for CRD establishment under HookOnlyStrategy")
assert.Contains(t, err.Error(), "CRD not yet established")
assert.Equal(t, kube.StatusWatcherStrategy, fakeClient.requestedStrategy, "CRD establishment wait must not use HookOnlyStrategy's no-op waiter")
require.NoError(t, instAction.installCRDs(crdsToInstall))
assert.Equal(t, []kube.WaitStrategy{kube.StatusWatcherStrategy}, failingKubeClient.RecordedWaitStrategies)
}
func TestCheckDependencies(t *testing.T) {

@ -50,7 +50,9 @@ type FailingKubeClient struct {
WaitDuration time.Duration
// RecordedWaitOptions stores the WaitOptions passed to GetWaiter for testing
RecordedWaitOptions []kube.WaitOption
mu sync.Mutex
// RecordedWaitStrategies stores the WaitStrategy passed to each GetWaiter call for testing
RecordedWaitStrategies []kube.WaitStrategy
mu sync.Mutex
}
var _ kube.Interface = &FailingKubeClient{}
@ -160,14 +162,15 @@ func (f *FailingKubeClient) GetWaiter(ws kube.WaitStrategy) (kube.Waiter, error)
return f.GetWaiterWithOptions(ws)
}
func (f *FailingKubeClient) appendRecordedWaitOptionsLocked(opts ...kube.WaitOption) {
func (f *FailingKubeClient) recordGetWaiterCallLocked(ws kube.WaitStrategy, opts ...kube.WaitOption) {
f.mu.Lock()
defer f.mu.Unlock()
f.RecordedWaitStrategies = append(f.RecordedWaitStrategies, ws)
f.RecordedWaitOptions = append(f.RecordedWaitOptions, opts...)
}
func (f *FailingKubeClient) GetWaiterWithOptions(ws kube.WaitStrategy, opts ...kube.WaitOption) (kube.Waiter, error) {
f.appendRecordedWaitOptionsLocked(opts...)
f.recordGetWaiterCallLocked(ws, opts...)
waiter, _ := f.PrintingKubeClient.GetWaiterWithOptions(ws, opts...)
printingKubeWaiter, _ := waiter.(*PrintingKubeWaiter)
return &FailingKubeWaiter{

Loading…
Cancel
Save