@@ -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+ }
0 commit comments