| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- /*
- Copyright © 2025 ESO Maintainer Team
- 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
- https://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 externalsecret
- import (
- "context"
- "fmt"
- "testing"
- "time"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/types"
- toolscache "k8s.io/client-go/tools/cache"
- "k8s.io/client-go/util/workqueue"
- ctrl "sigs.k8s.io/controller-runtime"
- runtimecache "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client"
- )
- type fakeInformer struct{}
- func (f *fakeInformer) AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error) {
- return nil, nil
- }
- func (f *fakeInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, _ time.Duration) (toolscache.ResourceEventHandlerRegistration, error) {
- return nil, nil
- }
- func (f *fakeInformer) AddEventHandlerWithOptions(handler toolscache.ResourceEventHandler, _ toolscache.HandlerOptions) (toolscache.ResourceEventHandlerRegistration, error) {
- return nil, nil
- }
- func (f *fakeInformer) RemoveEventHandler(_ toolscache.ResourceEventHandlerRegistration) error {
- return nil
- }
- func (f *fakeInformer) AddIndexers(indexers toolscache.Indexers) error {
- return nil
- }
- func (f *fakeInformer) HasSynced() bool {
- return true
- }
- func (f *fakeInformer) IsStopped() bool {
- return false
- }
- type fakeCache struct {
- runtimecache.Cache
- getInformerCalled bool
- getInformerObj client.Object
- getInformerErr error
- }
- func (f *fakeCache) GetInformer(ctx context.Context, obj client.Object, opts ...runtimecache.InformerGetOption) (runtimecache.Informer, error) {
- f.getInformerCalled = true
- f.getInformerObj = obj
- if f.getInformerErr != nil {
- return nil, f.getInformerErr
- }
- return &fakeInformer{}, nil
- }
- func TestEnsureInformer_UsesUnstructured(t *testing.T) {
- fc := &fakeCache{}
- log := ctrl.Log.WithName("test")
- m := &DefaultInformerManager{
- managerContext: context.Background(),
- cache: fc,
- log: log,
- informers: make(map[string]*informerEntry),
- queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[ctrl.Request]()),
- }
- gvk := schema.GroupVersionKind{
- Group: "monitoring.example.io",
- Version: "v1alpha1",
- Kind: "CustomNotifier",
- }
- es := types.NamespacedName{Name: "test-es", Namespace: "default"}
- created, err := m.EnsureInformer(context.Background(), gvk, es)
- require.NoError(t, err)
- assert.True(t, created)
- assert.True(t, fc.getInformerCalled, "GetInformer should be called")
- obj, ok := fc.getInformerObj.(*unstructured.Unstructured)
- require.True(t, ok, "GetInformer should be called with *unstructured.Unstructured")
- assert.Equal(t, gvk, obj.GroupVersionKind())
- }
- func TestEnsureInformer_DeduplicatesExistingGVK(t *testing.T) {
- fc := &fakeCache{}
- log := ctrl.Log.WithName("test")
- m := &DefaultInformerManager{
- managerContext: context.Background(),
- cache: fc,
- log: log,
- informers: make(map[string]*informerEntry),
- queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[ctrl.Request]()),
- }
- gvk := schema.GroupVersionKind{Group: "example.io", Version: "v1", Kind: "Foo"}
- es1 := types.NamespacedName{Name: "es-1", Namespace: "default"}
- es2 := types.NamespacedName{Name: "es-2", Namespace: "default"}
- created, err := m.EnsureInformer(context.Background(), gvk, es1)
- require.NoError(t, err)
- assert.True(t, created)
- fc.getInformerCalled = false
- created, err = m.EnsureInformer(context.Background(), gvk, es2)
- require.NoError(t, err)
- assert.False(t, created)
- assert.False(t, fc.getInformerCalled, "GetInformer should not be called again for same GVK")
- entry := m.informers[gvk.String()]
- assert.Len(t, entry.externalSecrets, 2)
- }
- func TestEnsureInformer_ErrorWhenQueueNotSet(t *testing.T) {
- fc := &fakeCache{}
- log := ctrl.Log.WithName("test")
- m := &DefaultInformerManager{
- managerContext: context.Background(),
- cache: fc,
- log: log,
- informers: make(map[string]*informerEntry),
- }
- gvk := schema.GroupVersionKind{Group: "example.io", Version: "v1", Kind: "Foo"}
- es := types.NamespacedName{Name: "es-1", Namespace: "default"}
- _, err := m.EnsureInformer(context.Background(), gvk, es)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "queue not initialized")
- }
- func TestEnsureInformer_PropagatesCacheError(t *testing.T) {
- fc := &fakeCache{
- getInformerErr: fmt.Errorf("CRD not found"),
- }
- log := ctrl.Log.WithName("test")
- m := &DefaultInformerManager{
- managerContext: context.Background(),
- cache: fc,
- log: log,
- informers: make(map[string]*informerEntry),
- queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[ctrl.Request]()),
- }
- gvk := schema.GroupVersionKind{Group: "example.io", Version: "v1", Kind: "Foo"}
- es := types.NamespacedName{Name: "es-1", Namespace: "default"}
- _, err := m.EnsureInformer(context.Background(), gvk, es)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "CRD not found")
- }
- func TestReleaseInformer_RemovesES(t *testing.T) {
- fc := &fakeCache{}
- log := ctrl.Log.WithName("test")
- m := &DefaultInformerManager{
- managerContext: context.Background(),
- cache: fc,
- log: log,
- informers: make(map[string]*informerEntry),
- queue: workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[ctrl.Request]()),
- }
- gvk := schema.GroupVersionKind{Group: "example.io", Version: "v1", Kind: "Foo"}
- es1 := types.NamespacedName{Name: "es-1", Namespace: "default"}
- es2 := types.NamespacedName{Name: "es-2", Namespace: "default"}
- _, err := m.EnsureInformer(context.Background(), gvk, es1)
- require.NoError(t, err)
- _, err = m.EnsureInformer(context.Background(), gvk, es2)
- require.NoError(t, err)
- err = m.ReleaseInformer(context.Background(), gvk, es1)
- require.NoError(t, err)
- assert.True(t, m.IsManaged(gvk))
- entry := m.informers[gvk.String()]
- assert.Len(t, entry.externalSecrets, 1)
- }
|