From c0addb352e284feda34667f0a36c06da9f1cf2a6 Mon Sep 17 00:00:00 2001 From: Joe Betz Date: Thu, 5 Mar 2026 20:06:01 -0500 Subject: [PATCH] Fix informer factory generation and add test --- .../src/k8s.io/client-go/informers/factory.go | 4 +- .../cmd/informer-gen/generators/factory.go | 4 +- .../informers/externalversions/factory.go | 4 +- .../externalversions/factory_test.go | 111 ++++++++++++++++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory_test.go diff --git a/staging/src/k8s.io/client-go/informers/factory.go b/staging/src/k8s.io/client-go/informers/factory.go index c7c735fed27..19901079f8b 100644 --- a/staging/src/k8s.io/client-go/informers/factory.go +++ b/staging/src/k8s.io/client-go/informers/factory.go @@ -256,7 +256,9 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal } informer = newFunc(f.client, resyncPeriod) - informer.SetTransform(f.transform) + if f.transform != nil { + informer.SetTransform(f.transform) + } f.informers[informerType] = informer return informer diff --git a/staging/src/k8s.io/code-generator/cmd/informer-gen/generators/factory.go b/staging/src/k8s.io/code-generator/cmd/informer-gen/generators/factory.go index b3ab50d0944..237de9342fa 100644 --- a/staging/src/k8s.io/code-generator/cmd/informer-gen/generators/factory.go +++ b/staging/src/k8s.io/code-generator/cmd/informer-gen/generators/factory.go @@ -313,7 +313,9 @@ func (f *sharedInformerFactory) InformerFor(obj {{.runtimeObject|raw}}, newFunc } informer = newFunc(f.client, resyncPeriod) - informer.SetTransform(f.transform) + if f.transform != nil { + informer.SetTransform(f.transform) + } f.informers[informerType] = informer return informer diff --git a/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory.go b/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory.go index 4d3d6384997..326e025b95a 100644 --- a/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory.go +++ b/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory.go @@ -237,7 +237,9 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal } informer = newFunc(f.client, resyncPeriod) - informer.SetTransform(f.transform) + if f.transform != nil { + informer.SetTransform(f.transform) + } f.informers[informerType] = informer return informer diff --git a/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory_test.go b/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory_test.go new file mode 100644 index 00000000000..bc1911121e5 --- /dev/null +++ b/staging/src/k8s.io/code-generator/examples/single/informers/externalversions/factory_test.go @@ -0,0 +1,111 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package externalversions + +import ( + "slices" + "testing" + "time" + + "k8s.io/client-go/tools/cache" + singleapiv1 "k8s.io/code-generator/examples/single/api/v1" + "k8s.io/code-generator/examples/single/clientset/versioned" +) + +// TestTransforms verified that transform calls are applied as expected. +func TestTransforms(t *testing.T) { + tests := []struct { + name string + useFactoryTransform bool + usePerInformerTransform bool + wantTransformCalls []string + }{ + { + name: "no transforms", + wantTransformCalls: nil, + }, + { + name: "no factory transform preserves per-informer transform", + usePerInformerTransform: true, + wantTransformCalls: []string{"per-informer"}, + }, + { + name: "factory transform applied when no per-informer transform", + useFactoryTransform: true, + wantTransformCalls: []string{"factory"}, + }, + { + name: "factory transform overrides per-informer transform", + useFactoryTransform: true, + usePerInformerTransform: true, + wantTransformCalls: []string{"factory"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var transformCalls []string + makeTransform := func(name string) cache.TransformFunc { + return func(obj interface{}) (interface{}, error) { + transformCalls = append(transformCalls, name) + return obj, nil + } + } + + var opts []SharedInformerOption + if tt.useFactoryTransform { + opts = append(opts, WithTransform(makeTransform("factory"))) + } + factory := NewSharedInformerFactoryWithOptions(nil, 0, opts...) + + var wrapper *transformTrackingInformer + newFunc := func(_ versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + inner := cache.NewSharedIndexInformer(nil, &singleapiv1.TestType{}, resyncPeriod, cache.Indexers{}) + wrapper = &transformTrackingInformer{SharedIndexInformer: inner} + if tt.usePerInformerTransform { + err := wrapper.SetTransform(makeTransform("per-informer")) + if err != nil { + t.Fatalf("failed to set transform: %v", err) + } + } + return wrapper + } + factory.InformerFor(&singleapiv1.TestType{}, newFunc) + + if wrapper.lastTransform != nil { + _, err := wrapper.lastTransform(nil) + if err != nil { + t.Fatalf("failed to invoke transform: %v", err) + } + } + + if !slices.Equal(transformCalls, tt.wantTransformCalls) { + t.Errorf("transform calls: got %v, want %v", transformCalls, tt.wantTransformCalls) + } + }) + } +} + +type transformTrackingInformer struct { + cache.SharedIndexInformer + lastTransform cache.TransformFunc +} + +func (s *transformTrackingInformer) SetTransform(handler cache.TransformFunc) error { + s.lastTransform = handler + return s.SharedIndexInformer.SetTransform(handler) +}