Skip to content

Commit 3117b04

Browse files
authored
Merge pull request #3434 from alvaroaleman/testcachesync
🌱 Test cache reader waits for cache sync
2 parents 83b689c + 717f6a7 commit 3117b04

2 files changed

Lines changed: 79 additions & 2 deletions

File tree

pkg/cache/cache_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"slices"
2525
"strconv"
2626
"strings"
27+
"testing"
28+
"testing/synctest"
2729
"time"
2830

2931
. "github.com/onsi/ginkgo/v2"
@@ -2588,3 +2590,70 @@ func cancelledCtx(ctx context.Context) context.Context {
25882590
cancel()
25892591
return cancelCtx
25902592
}
2593+
2594+
type fakeRESTMapper struct {
2595+
meta.RESTMapper
2596+
}
2597+
2598+
func (f *fakeRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
2599+
return &meta.RESTMapping{Scope: meta.RESTScopeNamespace}, nil
2600+
}
2601+
2602+
func TestReaderWaitsForCacheSync(t *testing.T) {
2603+
t.Parallel()
2604+
for _, readerFailOnMissingInformer := range []bool{true, false} {
2605+
t.Run(fmt.Sprintf("ReaderFailOnMissingInformer=%v", readerFailOnMissingInformer), func(t *testing.T) {
2606+
t.Parallel()
2607+
synctest.Test(t, func(t *testing.T) {
2608+
g := NewWithT(t)
2609+
2610+
fakeInformer := &controllertest.FakeInformer{Synced: false}
2611+
c, err := cache.New(&rest.Config{}, cache.Options{
2612+
ReaderFailOnMissingInformer: readerFailOnMissingInformer,
2613+
Mapper: &fakeRESTMapper{},
2614+
NewInformer: func(kcache.ListerWatcher, runtime.Object, time.Duration, kcache.Indexers) kcache.SharedIndexInformer {
2615+
return fakeInformer
2616+
},
2617+
})
2618+
g.Expect(err).NotTo(HaveOccurred())
2619+
2620+
ctx, cancel := context.WithCancel(t.Context())
2621+
defer cancel()
2622+
cacheDone := make(chan struct{})
2623+
go func() {
2624+
g.Expect(c.Start(ctx)).To(Succeed())
2625+
close(cacheDone)
2626+
}()
2627+
synctest.Wait() // Let the cache finish starting
2628+
_, err = c.GetInformer(ctx, &corev1.Service{}, cache.BlockUntilSynced(false))
2629+
g.Expect(err).ToNot(HaveOccurred())
2630+
2631+
listCtx, listCtxCancel := context.WithTimeout(ctx, time.Second)
2632+
defer listCtxCancel()
2633+
services := &corev1.ServiceList{}
2634+
err = c.List(listCtx, services)
2635+
g.Expect(err).To(HaveOccurred())
2636+
g.Expect(apierrors.IsTimeout(err)).To(BeTrue())
2637+
2638+
getCtx, getCtxCancel := context.WithTimeout(ctx, time.Second)
2639+
defer getCtxCancel()
2640+
err = c.Get(getCtx, client.ObjectKey{Name: "default", Namespace: "kubernetes"}, &corev1.Service{})
2641+
g.Expect(err).To(HaveOccurred())
2642+
g.Expect(apierrors.IsTimeout(err)).To(BeTrue())
2643+
2644+
fakeInformer.SyncedLock.Lock()
2645+
fakeInformer.Synced = true
2646+
fakeInformer.SyncedLock.Unlock()
2647+
2648+
g.Expect(c.List(ctx, services)).To(Succeed())
2649+
2650+
err = c.Get(getCtx, client.ObjectKey{Name: "default", Namespace: "kubernetes"}, &corev1.Service{})
2651+
g.Expect(err).To(HaveOccurred())
2652+
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
2653+
2654+
cancel()
2655+
<-cacheDone
2656+
})
2657+
})
2658+
}
2659+
}

pkg/controller/controllertest/util.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllertest
1818

1919
import (
2020
"context"
21+
"sync"
2122
"time"
2223

2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,7 +30,8 @@ var _ cache.SharedIndexInformer = &FakeInformer{}
2930
// FakeInformer provides fake Informer functionality for testing.
3031
type FakeInformer struct {
3132
// Synced is returned by the HasSynced functions to implement the Informer interface
32-
Synced bool
33+
Synced bool
34+
SyncedLock sync.Mutex
3335

3436
// RunCount is incremented each time RunInformersAndControllers is called
3537
RunCount int
@@ -44,6 +46,9 @@ type fakeHandlerRegistration struct {
4446

4547
// HasSynced implements cache.ResourceEventHandlerRegistration.
4648
func (f *fakeHandlerRegistration) HasSynced() bool {
49+
f.informer.SyncedLock.Lock()
50+
defer f.informer.SyncedLock.Unlock()
51+
4752
return f.informer.Synced
4853
}
4954

@@ -54,7 +59,7 @@ func (f *FakeInformer) AddIndexers(indexers cache.Indexers) error {
5459

5560
// GetIndexer does nothing. TODO(community): Implement this.
5661
func (f *FakeInformer) GetIndexer() cache.Indexer {
57-
return nil
62+
return cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, nil)
5863
}
5964

6065
// Informer returns the fake Informer.
@@ -64,6 +69,9 @@ func (f *FakeInformer) Informer() cache.SharedIndexInformer {
6469

6570
// HasSynced implements the Informer interface. Returns f.Synced.
6671
func (f *FakeInformer) HasSynced() bool {
72+
f.SyncedLock.Lock()
73+
defer f.SyncedLock.Unlock()
74+
6775
return f.Synced
6876
}
6977

0 commit comments

Comments
 (0)