k8s.io/apiserver@v0.29.3/pkg/storage/cacher/cacher_whitebox_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cacher
    18  
    19  import (
    20  	"context"
    21  	"crypto/rand"
    22  	"errors"
    23  	"fmt"
    24  	"reflect"
    25  	goruntime "runtime"
    26  	"strconv"
    27  	"sync"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/stretchr/testify/require"
    32  	"google.golang.org/grpc/metadata"
    33  
    34  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    35  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    36  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    37  	"k8s.io/apimachinery/pkg/fields"
    38  	"k8s.io/apimachinery/pkg/labels"
    39  	"k8s.io/apimachinery/pkg/runtime"
    40  	"k8s.io/apimachinery/pkg/runtime/schema"
    41  	"k8s.io/apimachinery/pkg/util/wait"
    42  	"k8s.io/apimachinery/pkg/watch"
    43  	"k8s.io/apiserver/pkg/apis/example"
    44  	examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
    45  	"k8s.io/apiserver/pkg/features"
    46  	"k8s.io/apiserver/pkg/storage"
    47  	etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
    48  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    49  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    50  	"k8s.io/utils/clock"
    51  	testingclock "k8s.io/utils/clock/testing"
    52  	"k8s.io/utils/pointer"
    53  )
    54  
    55  func newTestCacher(s storage.Interface) (*Cacher, storage.Versioner, error) {
    56  	prefix := "pods"
    57  	config := Config{
    58  		Storage:        s,
    59  		Versioner:      storage.APIObjectVersioner{},
    60  		GroupResource:  schema.GroupResource{Resource: "pods"},
    61  		ResourcePrefix: prefix,
    62  		KeyFunc:        func(obj runtime.Object) (string, error) { return storage.NamespaceKeyFunc(prefix, obj) },
    63  		GetAttrsFunc: func(obj runtime.Object) (labels.Set, fields.Set, error) {
    64  			pod, ok := obj.(*example.Pod)
    65  			if !ok {
    66  				return storage.DefaultNamespaceScopedAttr(obj)
    67  			}
    68  			labelsSet, fieldsSet, err := storage.DefaultNamespaceScopedAttr(obj)
    69  			if err != nil {
    70  				return nil, nil, err
    71  			}
    72  			fieldsSet["spec.nodeName"] = pod.Spec.NodeName
    73  			return labelsSet, fieldsSet, nil
    74  		},
    75  		NewFunc:     func() runtime.Object { return &example.Pod{} },
    76  		NewListFunc: func() runtime.Object { return &example.PodList{} },
    77  		Codec:       codecs.LegacyCodec(examplev1.SchemeGroupVersion),
    78  		Clock:       clock.RealClock{},
    79  	}
    80  	cacher, err := NewCacherFromConfig(config)
    81  	return cacher, storage.APIObjectVersioner{}, err
    82  }
    83  
    84  type dummyStorage struct {
    85  	sync.RWMutex
    86  	err       error
    87  	getListFn func(_ context.Context, _ string, _ storage.ListOptions, listObj runtime.Object) error
    88  	watchFn   func(_ context.Context, _ string, _ storage.ListOptions) (watch.Interface, error)
    89  }
    90  
    91  func (d *dummyStorage) RequestWatchProgress(ctx context.Context) error {
    92  	return nil
    93  }
    94  
    95  type dummyWatch struct {
    96  	ch chan watch.Event
    97  }
    98  
    99  func (w *dummyWatch) ResultChan() <-chan watch.Event {
   100  	return w.ch
   101  }
   102  
   103  func (w *dummyWatch) Stop() {
   104  	close(w.ch)
   105  }
   106  
   107  func newDummyWatch() watch.Interface {
   108  	return &dummyWatch{
   109  		ch: make(chan watch.Event),
   110  	}
   111  }
   112  
   113  func (d *dummyStorage) Versioner() storage.Versioner { return nil }
   114  func (d *dummyStorage) Create(_ context.Context, _ string, _, _ runtime.Object, _ uint64) error {
   115  	return fmt.Errorf("unimplemented")
   116  }
   117  func (d *dummyStorage) Delete(_ context.Context, _ string, _ runtime.Object, _ *storage.Preconditions, _ storage.ValidateObjectFunc, _ runtime.Object) error {
   118  	return fmt.Errorf("unimplemented")
   119  }
   120  func (d *dummyStorage) Watch(ctx context.Context, key string, opts storage.ListOptions) (watch.Interface, error) {
   121  	if d.watchFn != nil {
   122  		return d.watchFn(ctx, key, opts)
   123  	}
   124  	d.RLock()
   125  	defer d.RUnlock()
   126  
   127  	return newDummyWatch(), d.err
   128  }
   129  func (d *dummyStorage) Get(_ context.Context, _ string, _ storage.GetOptions, _ runtime.Object) error {
   130  	d.RLock()
   131  	defer d.RUnlock()
   132  
   133  	return d.err
   134  }
   135  func (d *dummyStorage) GetList(ctx context.Context, resPrefix string, opts storage.ListOptions, listObj runtime.Object) error {
   136  	if d.getListFn != nil {
   137  		return d.getListFn(ctx, resPrefix, opts, listObj)
   138  	}
   139  	d.RLock()
   140  	defer d.RUnlock()
   141  	podList := listObj.(*example.PodList)
   142  	podList.ListMeta = metav1.ListMeta{ResourceVersion: "100"}
   143  	return d.err
   144  }
   145  func (d *dummyStorage) GuaranteedUpdate(_ context.Context, _ string, _ runtime.Object, _ bool, _ *storage.Preconditions, _ storage.UpdateFunc, _ runtime.Object) error {
   146  	return fmt.Errorf("unimplemented")
   147  }
   148  func (d *dummyStorage) Count(_ string) (int64, error) {
   149  	return 0, fmt.Errorf("unimplemented")
   150  }
   151  func (d *dummyStorage) injectError(err error) {
   152  	d.Lock()
   153  	defer d.Unlock()
   154  
   155  	d.err = err
   156  }
   157  
   158  func TestGetListCacheBypass(t *testing.T) {
   159  	type testCase struct {
   160  		opts         storage.ListOptions
   161  		expectBypass bool
   162  	}
   163  	commonTestCases := []testCase{
   164  		{opts: storage.ListOptions{ResourceVersion: "0"}, expectBypass: false},
   165  		{opts: storage.ListOptions{ResourceVersion: "1"}, expectBypass: false},
   166  
   167  		{opts: storage.ListOptions{ResourceVersion: "", Predicate: storage.SelectionPredicate{Continue: "a"}}, expectBypass: true},
   168  		{opts: storage.ListOptions{ResourceVersion: "0", Predicate: storage.SelectionPredicate{Continue: "a"}}, expectBypass: true},
   169  		{opts: storage.ListOptions{ResourceVersion: "1", Predicate: storage.SelectionPredicate{Continue: "a"}}, expectBypass: true},
   170  
   171  		{opts: storage.ListOptions{ResourceVersion: "", Predicate: storage.SelectionPredicate{Limit: 500}}, expectBypass: true},
   172  		{opts: storage.ListOptions{ResourceVersion: "0", Predicate: storage.SelectionPredicate{Limit: 500}}, expectBypass: false},
   173  		{opts: storage.ListOptions{ResourceVersion: "1", Predicate: storage.SelectionPredicate{Limit: 500}}, expectBypass: true},
   174  
   175  		{opts: storage.ListOptions{ResourceVersion: "", ResourceVersionMatch: metav1.ResourceVersionMatchExact}, expectBypass: true},
   176  		{opts: storage.ListOptions{ResourceVersion: "0", ResourceVersionMatch: metav1.ResourceVersionMatchExact}, expectBypass: true},
   177  		{opts: storage.ListOptions{ResourceVersion: "1", ResourceVersionMatch: metav1.ResourceVersionMatchExact}, expectBypass: true},
   178  	}
   179  
   180  	t.Run("ConsistentListFromStorage", func(t *testing.T) {
   181  		defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)()
   182  		testCases := append(commonTestCases,
   183  			testCase{opts: storage.ListOptions{ResourceVersion: ""}, expectBypass: true},
   184  		)
   185  		for _, tc := range testCases {
   186  			testGetListCacheBypass(t, tc.opts, tc.expectBypass)
   187  		}
   188  
   189  	})
   190  	t.Run("ConsistentListFromCache", func(t *testing.T) {
   191  		defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, true)()
   192  		testCases := append(commonTestCases,
   193  			testCase{opts: storage.ListOptions{ResourceVersion: ""}, expectBypass: false},
   194  		)
   195  		for _, tc := range testCases {
   196  			testGetListCacheBypass(t, tc.opts, tc.expectBypass)
   197  		}
   198  	})
   199  }
   200  
   201  func testGetListCacheBypass(t *testing.T, options storage.ListOptions, expectBypass bool) {
   202  	backingStorage := &dummyStorage{}
   203  	cacher, _, err := newTestCacher(backingStorage)
   204  	if err != nil {
   205  		t.Fatalf("Couldn't create cacher: %v", err)
   206  	}
   207  	defer cacher.Stop()
   208  
   209  	result := &example.PodList{}
   210  
   211  	// Wait until cacher is initialized.
   212  	if err := cacher.ready.wait(context.Background()); err != nil {
   213  		t.Fatalf("unexpected error waiting for the cache to be ready")
   214  	}
   215  	// Inject error to underlying layer and check if cacher is not bypassed.
   216  	backingStorage.getListFn = func(_ context.Context, key string, opts storage.ListOptions, listObj runtime.Object) error {
   217  		currentResourceVersion := "42"
   218  		switch {
   219  		// request made by getCurrentResourceVersionFromStorage by checking Limit
   220  		case key == cacher.resourcePrefix:
   221  			podList := listObj.(*example.PodList)
   222  			podList.ResourceVersion = currentResourceVersion
   223  			return nil
   224  		// request made by storage.GetList with revision from original request or
   225  		// returned by getCurrentResourceVersionFromStorage
   226  		case opts.ResourceVersion == options.ResourceVersion || opts.ResourceVersion == currentResourceVersion:
   227  			return errDummy
   228  		default:
   229  			t.Fatalf("Unexpected request %+v", opts)
   230  			return nil
   231  		}
   232  	}
   233  	err = cacher.GetList(context.TODO(), "pods/ns", options, result)
   234  	if err != nil && err != errDummy {
   235  		t.Fatalf("Unexpected error for List request with options: %v, err: %v", options, err)
   236  	}
   237  	gotBypass := err == errDummy
   238  	if gotBypass != expectBypass {
   239  		t.Errorf("Unexpected bypass result for List request with options %+v, bypass expected: %v, got: %v", options, expectBypass, gotBypass)
   240  	}
   241  }
   242  
   243  func TestGetListNonRecursiveCacheBypass(t *testing.T) {
   244  	backingStorage := &dummyStorage{}
   245  	cacher, _, err := newTestCacher(backingStorage)
   246  	if err != nil {
   247  		t.Fatalf("Couldn't create cacher: %v", err)
   248  	}
   249  	defer cacher.Stop()
   250  
   251  	pred := storage.SelectionPredicate{
   252  		Limit: 500,
   253  	}
   254  	result := &example.PodList{}
   255  
   256  	// Wait until cacher is initialized.
   257  	if err := cacher.ready.wait(context.Background()); err != nil {
   258  		t.Fatalf("unexpected error waiting for the cache to be ready")
   259  	}
   260  
   261  	// Inject error to underlying layer and check if cacher is not bypassed.
   262  	backingStorage.injectError(errDummy)
   263  	err = cacher.GetList(context.TODO(), "pods/ns", storage.ListOptions{
   264  		ResourceVersion: "0",
   265  		Predicate:       pred,
   266  	}, result)
   267  	if err != nil {
   268  		t.Errorf("GetList with Limit and RV=0 should be served from cache: %v", err)
   269  	}
   270  
   271  	err = cacher.GetList(context.TODO(), "pods/ns", storage.ListOptions{
   272  		ResourceVersion: "",
   273  		Predicate:       pred,
   274  	}, result)
   275  	if err != errDummy {
   276  		t.Errorf("GetList with Limit without RV=0 should bypass cacher: %v", err)
   277  	}
   278  }
   279  
   280  func TestGetCacheBypass(t *testing.T) {
   281  	backingStorage := &dummyStorage{}
   282  	cacher, _, err := newTestCacher(backingStorage)
   283  	if err != nil {
   284  		t.Fatalf("Couldn't create cacher: %v", err)
   285  	}
   286  	defer cacher.Stop()
   287  
   288  	result := &example.Pod{}
   289  
   290  	// Wait until cacher is initialized.
   291  	if err := cacher.ready.wait(context.Background()); err != nil {
   292  		t.Fatalf("unexpected error waiting for the cache to be ready")
   293  	}
   294  
   295  	// Inject error to underlying layer and check if cacher is not bypassed.
   296  	backingStorage.injectError(errDummy)
   297  	err = cacher.Get(context.TODO(), "pods/ns/pod-0", storage.GetOptions{
   298  		IgnoreNotFound:  true,
   299  		ResourceVersion: "0",
   300  	}, result)
   301  	if err != nil {
   302  		t.Errorf("Get with RV=0 should be served from cache: %v", err)
   303  	}
   304  
   305  	err = cacher.Get(context.TODO(), "pods/ns/pod-0", storage.GetOptions{
   306  		IgnoreNotFound:  true,
   307  		ResourceVersion: "",
   308  	}, result)
   309  	if err != errDummy {
   310  		t.Errorf("Get without RV=0 should bypass cacher: %v", err)
   311  	}
   312  }
   313  
   314  func TestWatchCacheBypass(t *testing.T) {
   315  	backingStorage := &dummyStorage{}
   316  	cacher, _, err := newTestCacher(backingStorage)
   317  	if err != nil {
   318  		t.Fatalf("Couldn't create cacher: %v", err)
   319  	}
   320  	defer cacher.Stop()
   321  
   322  	// Wait until cacher is initialized.
   323  	if err := cacher.ready.wait(context.Background()); err != nil {
   324  		t.Fatalf("unexpected error waiting for the cache to be ready")
   325  	}
   326  
   327  	// Inject error to underlying layer and check if cacher is not bypassed.
   328  	backingStorage.injectError(errDummy)
   329  	_, err = cacher.Watch(context.TODO(), "pod/ns", storage.ListOptions{
   330  		ResourceVersion: "0",
   331  		Predicate:       storage.Everything,
   332  	})
   333  	if err != nil {
   334  		t.Errorf("Watch with RV=0 should be served from cache: %v", err)
   335  	}
   336  
   337  	// With unset RV, check if cacher is bypassed.
   338  	_, err = cacher.Watch(context.TODO(), "pod/ns", storage.ListOptions{
   339  		ResourceVersion: "",
   340  	})
   341  	if err != errDummy {
   342  		t.Errorf("Watch with unset RV should bypass cacher: %v", err)
   343  	}
   344  }
   345  
   346  func TestEmptyWatchEventCache(t *testing.T) {
   347  	server, etcdStorage := newEtcdTestStorage(t, etcd3testing.PathPrefix())
   348  	defer server.Terminate(t)
   349  
   350  	// add a few objects
   351  	v := storage.APIObjectVersioner{}
   352  	lastRV := uint64(0)
   353  	for i := 0; i < 5; i++ {
   354  		pod := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("foo-%d", i), Namespace: "test-ns"}}
   355  		out := &example.Pod{}
   356  		key := computePodKey(pod)
   357  		if err := etcdStorage.Create(context.Background(), key, pod, out, 0); err != nil {
   358  			t.Fatalf("Create failed: %v", err)
   359  		}
   360  		var err error
   361  		if lastRV, err = v.ParseResourceVersion(out.ResourceVersion); err != nil {
   362  			t.Fatalf("Unexpected error: %v", err)
   363  		}
   364  	}
   365  
   366  	cacher, _, err := newTestCacher(etcdStorage)
   367  	if err != nil {
   368  		t.Fatalf("Couldn't create cacher: %v", err)
   369  	}
   370  	defer cacher.Stop()
   371  
   372  	// Given that cacher is always initialized from the "current" version of etcd,
   373  	// we now have a cacher with an empty cache of watch events and a resourceVersion of rv.
   374  	// It should support establishing watches from rv and higher, but not older.
   375  
   376  	expectedResourceExpiredError := apierrors.NewResourceExpired("").ErrStatus
   377  	tests := []struct {
   378  		name            string
   379  		resourceVersion uint64
   380  		expectedEvent   *watch.Event
   381  	}{
   382  		{
   383  			name:            "RV-1",
   384  			resourceVersion: lastRV - 1,
   385  			expectedEvent:   &watch.Event{Type: watch.Error, Object: &expectedResourceExpiredError},
   386  		},
   387  		{
   388  			name:            "RV",
   389  			resourceVersion: lastRV,
   390  		},
   391  		{
   392  			name:            "RV+1",
   393  			resourceVersion: lastRV + 1,
   394  		},
   395  	}
   396  
   397  	for _, tt := range tests {
   398  		t.Run(tt.name, func(t *testing.T) {
   399  			opts := storage.ListOptions{
   400  				ResourceVersion: strconv.Itoa(int(tt.resourceVersion)),
   401  				Predicate:       storage.Everything,
   402  			}
   403  			watcher, err := cacher.Watch(context.Background(), "/pods/test-ns", opts)
   404  			if err != nil {
   405  				t.Fatalf("Failed to create watch: %v", err)
   406  			}
   407  			defer watcher.Stop()
   408  			select {
   409  			case event := <-watcher.ResultChan():
   410  				if tt.expectedEvent == nil {
   411  					t.Errorf("Unexpected event: type=%#v, object=%#v", event.Type, event.Object)
   412  					break
   413  				}
   414  				if e, a := tt.expectedEvent.Type, event.Type; e != a {
   415  					t.Errorf("Expected: %s, got: %s", e, a)
   416  				}
   417  				if e, a := tt.expectedEvent.Object, event.Object; !apiequality.Semantic.DeepDerivative(e, a) {
   418  					t.Errorf("Expected: %#v, got: %#v", e, a)
   419  				}
   420  			case <-time.After(3 * time.Second):
   421  				if tt.expectedEvent != nil {
   422  					t.Errorf("Failed to get an event")
   423  				}
   424  				// watch remained established successfully
   425  			}
   426  		})
   427  	}
   428  }
   429  
   430  func TestWatchNotHangingOnStartupFailure(t *testing.T) {
   431  	// Configure cacher so that it can't initialize, because of
   432  	// constantly failing lists to the underlying storage.
   433  	dummyErr := fmt.Errorf("dummy")
   434  	backingStorage := &dummyStorage{err: dummyErr}
   435  	cacher, _, err := newTestCacher(backingStorage)
   436  	if err != nil {
   437  		t.Fatalf("Couldn't create cacher: %v", err)
   438  	}
   439  	defer cacher.Stop()
   440  
   441  	ctx, cancel := context.WithCancel(context.Background())
   442  	// Cancel the watch after some time to check if it will properly
   443  	// terminate instead of hanging forever.
   444  	go func() {
   445  		defer cancel()
   446  		cacher.clock.Sleep(5 * time.Second)
   447  	}()
   448  
   449  	// Watch hangs waiting on watchcache being initialized.
   450  	// Ensure that it terminates when its context is cancelled
   451  	// (e.g. the request is terminated for whatever reason).
   452  	_, err = cacher.Watch(ctx, "pods/ns", storage.ListOptions{ResourceVersion: "0"})
   453  	if err == nil || err.Error() != apierrors.NewServiceUnavailable(context.Canceled.Error()).Error() {
   454  		t.Errorf("Unexpected error: %#v", err)
   455  	}
   456  }
   457  
   458  func TestWatcherNotGoingBackInTime(t *testing.T) {
   459  	backingStorage := &dummyStorage{}
   460  	cacher, v, err := newTestCacher(backingStorage)
   461  	if err != nil {
   462  		t.Fatalf("Couldn't create cacher: %v", err)
   463  	}
   464  	defer cacher.Stop()
   465  
   466  	// Wait until cacher is initialized.
   467  	if err := cacher.ready.wait(context.Background()); err != nil {
   468  		t.Fatalf("unexpected error waiting for the cache to be ready")
   469  	}
   470  
   471  	// Ensure there is some budget for slowing down processing.
   472  	cacher.dispatchTimeoutBudget.returnUnused(100 * time.Millisecond)
   473  
   474  	makePod := func(i int) *examplev1.Pod {
   475  		return &examplev1.Pod{
   476  			ObjectMeta: metav1.ObjectMeta{
   477  				Name:            fmt.Sprintf("pod-%d", 1000+i),
   478  				Namespace:       "ns",
   479  				ResourceVersion: fmt.Sprintf("%d", 1000+i),
   480  			},
   481  		}
   482  	}
   483  	if err := cacher.watchCache.Add(makePod(0)); err != nil {
   484  		t.Errorf("error: %v", err)
   485  	}
   486  
   487  	totalPods := 100
   488  
   489  	// Create watcher that will be slowing down reading.
   490  	w1, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{
   491  		ResourceVersion: "999",
   492  		Predicate:       storage.Everything,
   493  	})
   494  	if err != nil {
   495  		t.Fatalf("Failed to create watch: %v", err)
   496  	}
   497  	defer w1.Stop()
   498  	go func() {
   499  		a := 0
   500  		for range w1.ResultChan() {
   501  			time.Sleep(time.Millisecond)
   502  			a++
   503  			if a == 100 {
   504  				break
   505  			}
   506  		}
   507  	}()
   508  
   509  	// Now push a ton of object to cache.
   510  	for i := 1; i < totalPods; i++ {
   511  		cacher.watchCache.Add(makePod(i))
   512  	}
   513  
   514  	// Create fast watcher and ensure it will get each object exactly once.
   515  	w2, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{ResourceVersion: "999", Predicate: storage.Everything})
   516  	if err != nil {
   517  		t.Fatalf("Failed to create watch: %v", err)
   518  	}
   519  	defer w2.Stop()
   520  
   521  	shouldContinue := true
   522  	currentRV := uint64(0)
   523  	for shouldContinue {
   524  		select {
   525  		case event, ok := <-w2.ResultChan():
   526  			if !ok {
   527  				shouldContinue = false
   528  				break
   529  			}
   530  			rv, err := v.ParseResourceVersion(event.Object.(metaRuntimeInterface).GetResourceVersion())
   531  			if err != nil {
   532  				t.Errorf("unexpected parsing error: %v", err)
   533  			} else {
   534  				if rv < currentRV {
   535  					t.Errorf("watcher going back in time")
   536  				}
   537  				currentRV = rv
   538  			}
   539  		case <-time.After(time.Second):
   540  			w2.Stop()
   541  		}
   542  	}
   543  }
   544  
   545  func TestCacherDontAcceptRequestsStopped(t *testing.T) {
   546  	backingStorage := &dummyStorage{}
   547  	cacher, _, err := newTestCacher(backingStorage)
   548  	if err != nil {
   549  		t.Fatalf("Couldn't create cacher: %v", err)
   550  	}
   551  
   552  	// Wait until cacher is initialized.
   553  	if err := cacher.ready.wait(context.Background()); err != nil {
   554  		t.Fatalf("unexpected error waiting for the cache to be ready")
   555  	}
   556  
   557  	w, err := cacher.Watch(context.Background(), "pods/ns", storage.ListOptions{ResourceVersion: "0", Predicate: storage.Everything})
   558  	if err != nil {
   559  		t.Fatalf("Failed to create watch: %v", err)
   560  	}
   561  
   562  	watchClosed := make(chan struct{})
   563  	go func() {
   564  		defer close(watchClosed)
   565  		for event := range w.ResultChan() {
   566  			switch event.Type {
   567  			case watch.Added, watch.Modified, watch.Deleted:
   568  				// ok
   569  			default:
   570  				t.Errorf("unexpected event %#v", event)
   571  			}
   572  		}
   573  	}()
   574  
   575  	cacher.Stop()
   576  
   577  	_, err = cacher.Watch(context.Background(), "pods/ns", storage.ListOptions{ResourceVersion: "0", Predicate: storage.Everything})
   578  	if err == nil {
   579  		t.Fatalf("Success to create Watch: %v", err)
   580  	}
   581  
   582  	result := &example.Pod{}
   583  	err = cacher.Get(context.TODO(), "pods/ns/pod-0", storage.GetOptions{
   584  		IgnoreNotFound:  true,
   585  		ResourceVersion: "1",
   586  	}, result)
   587  	if err == nil {
   588  		t.Fatalf("Success to create Get: %v", err)
   589  	}
   590  
   591  	listResult := &example.PodList{}
   592  	err = cacher.GetList(context.TODO(), "pods/ns", storage.ListOptions{
   593  		ResourceVersion: "1",
   594  		Recursive:       true,
   595  	}, listResult)
   596  	if err == nil {
   597  		t.Fatalf("Success to create GetList: %v", err)
   598  	}
   599  
   600  	select {
   601  	case <-watchClosed:
   602  	case <-time.After(wait.ForeverTestTimeout):
   603  		t.Errorf("timed out waiting for watch to close")
   604  	}
   605  }
   606  
   607  func TestCacherDontMissEventsOnReinitialization(t *testing.T) {
   608  	makePod := func(i int) *example.Pod {
   609  		return &example.Pod{
   610  			ObjectMeta: metav1.ObjectMeta{
   611  				Name:            fmt.Sprintf("pod-%d", i),
   612  				Namespace:       "ns",
   613  				ResourceVersion: fmt.Sprintf("%d", i),
   614  			},
   615  		}
   616  	}
   617  
   618  	listCalls, watchCalls := 0, 0
   619  	backingStorage := &dummyStorage{
   620  		getListFn: func(_ context.Context, _ string, _ storage.ListOptions, listObj runtime.Object) error {
   621  			podList := listObj.(*example.PodList)
   622  			var err error
   623  			switch listCalls {
   624  			case 0:
   625  				podList.ListMeta = metav1.ListMeta{ResourceVersion: "1"}
   626  			case 1:
   627  				podList.ListMeta = metav1.ListMeta{ResourceVersion: "10"}
   628  			default:
   629  				err = fmt.Errorf("unexpected list call")
   630  			}
   631  			listCalls++
   632  			return err
   633  		},
   634  		watchFn: func(_ context.Context, _ string, _ storage.ListOptions) (watch.Interface, error) {
   635  			var w *watch.FakeWatcher
   636  			var err error
   637  			switch watchCalls {
   638  			case 0:
   639  				w = watch.NewFakeWithChanSize(10, false)
   640  				for i := 2; i < 8; i++ {
   641  					w.Add(makePod(i))
   642  				}
   643  				// Emit an error to force relisting.
   644  				w.Error(nil)
   645  				w.Stop()
   646  			case 1:
   647  				w = watch.NewFakeWithChanSize(10, false)
   648  				for i := 12; i < 18; i++ {
   649  					w.Add(makePod(i))
   650  				}
   651  				w.Stop()
   652  			default:
   653  				err = fmt.Errorf("unexpected watch call")
   654  			}
   655  			watchCalls++
   656  			return w, err
   657  		},
   658  	}
   659  	cacher, _, err := newTestCacher(backingStorage)
   660  	if err != nil {
   661  		t.Fatalf("Couldn't create cacher: %v", err)
   662  	}
   663  	defer cacher.Stop()
   664  
   665  	concurrency := 1000
   666  	wg := sync.WaitGroup{}
   667  	wg.Add(concurrency)
   668  
   669  	// Ensure that test doesn't deadlock if cacher already processed everything
   670  	// and get back into Pending state before some watches get called.
   671  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
   672  	defer cancel()
   673  
   674  	errCh := make(chan error, concurrency)
   675  	for i := 0; i < concurrency; i++ {
   676  		go func() {
   677  			defer wg.Done()
   678  			w, err := cacher.Watch(ctx, "pods", storage.ListOptions{ResourceVersion: "1", Predicate: storage.Everything})
   679  			if err != nil {
   680  				// Watch failed to initialize (this most probably means that cacher
   681  				// already moved back to Pending state before watch initialized.
   682  				// Ignore this case.
   683  				return
   684  			}
   685  			defer w.Stop()
   686  
   687  			prevRV := -1
   688  			for event := range w.ResultChan() {
   689  				if event.Type == watch.Error {
   690  					break
   691  				}
   692  				object := event.Object
   693  				if co, ok := object.(runtime.CacheableObject); ok {
   694  					object = co.GetObject()
   695  				}
   696  				rv, err := strconv.Atoi(object.(*example.Pod).ResourceVersion)
   697  				if err != nil {
   698  					errCh <- fmt.Errorf("incorrect resource version: %v", err)
   699  					return
   700  				}
   701  				if prevRV != -1 && prevRV+1 != rv {
   702  					errCh <- fmt.Errorf("unexpected event received, prevRV=%d, rv=%d", prevRV, rv)
   703  					return
   704  				}
   705  				prevRV = rv
   706  			}
   707  
   708  		}()
   709  	}
   710  	wg.Wait()
   711  	close(errCh)
   712  
   713  	for err := range errCh {
   714  		t.Error(err)
   715  	}
   716  }
   717  
   718  func TestCacherNoLeakWithMultipleWatchers(t *testing.T) {
   719  	backingStorage := &dummyStorage{}
   720  	cacher, _, err := newTestCacher(backingStorage)
   721  	if err != nil {
   722  		t.Fatalf("Couldn't create cacher: %v", err)
   723  	}
   724  	defer cacher.Stop()
   725  
   726  	// Wait until cacher is initialized.
   727  	if err := cacher.ready.wait(context.Background()); err != nil {
   728  		t.Fatalf("unexpected error waiting for the cache to be ready")
   729  	}
   730  	pred := storage.Everything
   731  	pred.AllowWatchBookmarks = true
   732  
   733  	// run the collision test for 3 seconds to let ~2 buckets expire
   734  	stopCh := make(chan struct{})
   735  	var watchErr error
   736  	time.AfterFunc(3*time.Second, func() { close(stopCh) })
   737  
   738  	wg := &sync.WaitGroup{}
   739  
   740  	wg.Add(1)
   741  	go func() {
   742  		defer wg.Done()
   743  		for {
   744  			select {
   745  			case <-stopCh:
   746  				return
   747  			default:
   748  				ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
   749  				defer cancel()
   750  				w, err := cacher.Watch(ctx, "pods/ns", storage.ListOptions{ResourceVersion: "0", Predicate: pred})
   751  				if err != nil {
   752  					watchErr = fmt.Errorf("Failed to create watch: %v", err)
   753  					return
   754  				}
   755  				w.Stop()
   756  			}
   757  		}
   758  	}()
   759  
   760  	wg.Add(1)
   761  	go func() {
   762  		defer wg.Done()
   763  		for {
   764  			select {
   765  			case <-stopCh:
   766  				return
   767  			default:
   768  				cacher.Lock()
   769  				cacher.bookmarkWatchers.popExpiredWatchersThreadUnsafe()
   770  				cacher.Unlock()
   771  			}
   772  		}
   773  	}()
   774  
   775  	// wait for adding/removing watchers to end
   776  	wg.Wait()
   777  
   778  	if watchErr != nil {
   779  		t.Fatal(watchErr)
   780  	}
   781  
   782  	// wait out the expiration period and pop expired watchers
   783  	time.Sleep(2 * time.Second)
   784  	cacher.Lock()
   785  	defer cacher.Unlock()
   786  	cacher.bookmarkWatchers.popExpiredWatchersThreadUnsafe()
   787  	if len(cacher.bookmarkWatchers.watchersBuckets) != 0 {
   788  		numWatchers := 0
   789  		for bucketID, v := range cacher.bookmarkWatchers.watchersBuckets {
   790  			numWatchers += len(v)
   791  			t.Errorf("there are %v watchers at bucket Id %v with start Id %v", len(v), bucketID, cacher.bookmarkWatchers.startBucketID)
   792  		}
   793  		t.Errorf("unexpected bookmark watchers %v", numWatchers)
   794  	}
   795  }
   796  
   797  func testCacherSendBookmarkEvents(t *testing.T, allowWatchBookmarks, expectedBookmarks bool) {
   798  	backingStorage := &dummyStorage{}
   799  	cacher, _, err := newTestCacher(backingStorage)
   800  	if err != nil {
   801  		t.Fatalf("Couldn't create cacher: %v", err)
   802  	}
   803  	defer cacher.Stop()
   804  
   805  	// Wait until cacher is initialized.
   806  	if err := cacher.ready.wait(context.Background()); err != nil {
   807  		t.Fatalf("unexpected error waiting for the cache to be ready")
   808  	}
   809  	pred := storage.Everything
   810  	pred.AllowWatchBookmarks = allowWatchBookmarks
   811  
   812  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
   813  	defer cancel()
   814  	w, err := cacher.Watch(ctx, "pods/ns", storage.ListOptions{ResourceVersion: "0", Predicate: pred})
   815  	if err != nil {
   816  		t.Fatalf("Failed to create watch: %v", err)
   817  	}
   818  
   819  	resourceVersion := uint64(1000)
   820  	errc := make(chan error, 1)
   821  	go func() {
   822  		deadline := time.Now().Add(time.Second)
   823  		for i := 0; time.Now().Before(deadline); i++ {
   824  			err := cacher.watchCache.Add(&examplev1.Pod{
   825  				ObjectMeta: metav1.ObjectMeta{
   826  					Name:            fmt.Sprintf("pod-%d", i),
   827  					Namespace:       "ns",
   828  					ResourceVersion: fmt.Sprintf("%v", resourceVersion+uint64(i)),
   829  				}})
   830  			if err != nil {
   831  				errc <- fmt.Errorf("failed to add a pod: %v", err)
   832  				return
   833  			}
   834  			time.Sleep(100 * time.Millisecond)
   835  		}
   836  	}()
   837  
   838  	timeoutCh := time.After(2 * time.Second)
   839  	lastObservedRV := uint64(0)
   840  	for {
   841  		select {
   842  		case err := <-errc:
   843  			t.Fatal(err)
   844  			return
   845  		case event, ok := <-w.ResultChan():
   846  			if !ok {
   847  				t.Fatal("Unexpected closed")
   848  			}
   849  			rv, err := cacher.versioner.ObjectResourceVersion(event.Object)
   850  			if err != nil {
   851  				t.Errorf("failed to parse resource version from %#v: %v", event.Object, err)
   852  			}
   853  			if event.Type == watch.Bookmark {
   854  				if !expectedBookmarks {
   855  					t.Fatalf("Unexpected bookmark events received")
   856  				}
   857  
   858  				if rv < lastObservedRV {
   859  					t.Errorf("Unexpected bookmark event resource version %v (last %v)", rv, lastObservedRV)
   860  				}
   861  				return
   862  			}
   863  			lastObservedRV = rv
   864  		case <-timeoutCh:
   865  			if expectedBookmarks {
   866  				t.Fatal("Unexpected timeout to receive a bookmark event")
   867  			}
   868  			return
   869  		}
   870  	}
   871  }
   872  
   873  func TestCacherSendBookmarkEvents(t *testing.T) {
   874  	testCases := []struct {
   875  		allowWatchBookmarks bool
   876  		expectedBookmarks   bool
   877  	}{
   878  		{
   879  			allowWatchBookmarks: true,
   880  			expectedBookmarks:   true,
   881  		},
   882  		{
   883  			allowWatchBookmarks: false,
   884  			expectedBookmarks:   false,
   885  		},
   886  	}
   887  
   888  	for _, tc := range testCases {
   889  		testCacherSendBookmarkEvents(t, tc.allowWatchBookmarks, tc.expectedBookmarks)
   890  	}
   891  }
   892  
   893  func TestCacherSendsMultipleWatchBookmarks(t *testing.T) {
   894  	backingStorage := &dummyStorage{}
   895  	cacher, _, err := newTestCacher(backingStorage)
   896  	if err != nil {
   897  		t.Fatalf("Couldn't create cacher: %v", err)
   898  	}
   899  	defer cacher.Stop()
   900  	// Update bookmarkFrequency to speed up test.
   901  	// Note that the frequency lower than 1s doesn't change much due to
   902  	// resolution how frequency we recompute.
   903  	cacher.bookmarkWatchers.bookmarkFrequency = time.Second
   904  
   905  	// Wait until cacher is initialized.
   906  	if err := cacher.ready.wait(context.Background()); err != nil {
   907  		t.Fatalf("unexpected error waiting for the cache to be ready")
   908  	}
   909  	pred := storage.Everything
   910  	pred.AllowWatchBookmarks = true
   911  
   912  	makePod := func(index int) *examplev1.Pod {
   913  		return &examplev1.Pod{
   914  			ObjectMeta: metav1.ObjectMeta{
   915  				Name:            fmt.Sprintf("pod-%d", index),
   916  				Namespace:       "ns",
   917  				ResourceVersion: fmt.Sprintf("%v", 100+index),
   918  			},
   919  		}
   920  	}
   921  
   922  	// Create pod to initialize watch cache.
   923  	if err := cacher.watchCache.Add(makePod(0)); err != nil {
   924  		t.Fatalf("failed to add a pod: %v", err)
   925  	}
   926  
   927  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   928  	defer cancel()
   929  	w, err := cacher.Watch(ctx, "pods/ns", storage.ListOptions{ResourceVersion: "100", Predicate: pred})
   930  	if err != nil {
   931  		t.Fatalf("Failed to create watch: %v", err)
   932  	}
   933  
   934  	// Create one more pod, to ensure that current RV is higher and thus
   935  	// bookmarks will be delievere (events are delivered for RV higher
   936  	// than the max from init events).
   937  	if err := cacher.watchCache.Add(makePod(1)); err != nil {
   938  		t.Fatalf("failed to add a pod: %v", err)
   939  	}
   940  
   941  	timeoutCh := time.After(5 * time.Second)
   942  	lastObservedRV := uint64(0)
   943  	// Ensure that a watcher gets two bookmarks.
   944  	for observedBookmarks := 0; observedBookmarks < 2; {
   945  		select {
   946  		case event, ok := <-w.ResultChan():
   947  			if !ok {
   948  				t.Fatal("Unexpected closed")
   949  			}
   950  			rv, err := cacher.versioner.ObjectResourceVersion(event.Object)
   951  			if err != nil {
   952  				t.Errorf("failed to parse resource version from %#v: %v", event.Object, err)
   953  			}
   954  			if event.Type == watch.Bookmark {
   955  				observedBookmarks++
   956  				if rv < lastObservedRV {
   957  					t.Errorf("Unexpected bookmark event resource version %v (last %v)", rv, lastObservedRV)
   958  				}
   959  			}
   960  			lastObservedRV = rv
   961  		case <-timeoutCh:
   962  			t.Fatal("Unexpected timeout to receive bookmark events")
   963  		}
   964  	}
   965  }
   966  
   967  func TestDispatchingBookmarkEventsWithConcurrentStop(t *testing.T) {
   968  	backingStorage := &dummyStorage{}
   969  	cacher, _, err := newTestCacher(backingStorage)
   970  	if err != nil {
   971  		t.Fatalf("Couldn't create cacher: %v", err)
   972  	}
   973  	defer cacher.Stop()
   974  
   975  	// Wait until cacher is initialized.
   976  	if err := cacher.ready.wait(context.Background()); err != nil {
   977  		t.Fatalf("unexpected error waiting for the cache to be ready")
   978  	}
   979  
   980  	// Ensure there is some budget for slowing down processing.
   981  	cacher.dispatchTimeoutBudget.returnUnused(100 * time.Millisecond)
   982  
   983  	resourceVersion := uint64(1000)
   984  	err = cacher.watchCache.Add(&examplev1.Pod{
   985  		ObjectMeta: metav1.ObjectMeta{
   986  			Name:            "pod-0",
   987  			Namespace:       "ns",
   988  			ResourceVersion: fmt.Sprintf("%v", resourceVersion),
   989  		}})
   990  	if err != nil {
   991  		t.Fatalf("failed to add a pod: %v", err)
   992  	}
   993  
   994  	for i := 0; i < 1000; i++ {
   995  		pred := storage.Everything
   996  		pred.AllowWatchBookmarks = true
   997  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   998  		defer cancel()
   999  		w, err := cacher.Watch(ctx, "pods/ns", storage.ListOptions{ResourceVersion: "999", Predicate: pred})
  1000  		if err != nil {
  1001  			t.Fatalf("Failed to create watch: %v", err)
  1002  		}
  1003  		bookmark := &watchCacheEvent{
  1004  			Type:            watch.Bookmark,
  1005  			ResourceVersion: uint64(i),
  1006  			Object:          cacher.newFunc(),
  1007  		}
  1008  		err = cacher.versioner.UpdateObject(bookmark.Object, bookmark.ResourceVersion)
  1009  		if err != nil {
  1010  			t.Fatalf("failure to update version of object (%d) %#v", bookmark.ResourceVersion, bookmark.Object)
  1011  		}
  1012  
  1013  		wg := sync.WaitGroup{}
  1014  		wg.Add(2)
  1015  		go func() {
  1016  			cacher.processEvent(bookmark)
  1017  			wg.Done()
  1018  		}()
  1019  
  1020  		go func() {
  1021  			w.Stop()
  1022  			wg.Done()
  1023  		}()
  1024  
  1025  		done := make(chan struct{})
  1026  		go func() {
  1027  			for range w.ResultChan() {
  1028  			}
  1029  			close(done)
  1030  		}()
  1031  
  1032  		select {
  1033  		case <-done:
  1034  		case <-time.After(time.Second):
  1035  			t.Fatal("receive result timeout")
  1036  		}
  1037  		w.Stop()
  1038  		wg.Wait()
  1039  	}
  1040  }
  1041  
  1042  func TestBookmarksOnResourceVersionUpdates(t *testing.T) {
  1043  	backingStorage := &dummyStorage{}
  1044  	cacher, _, err := newTestCacher(backingStorage)
  1045  	if err != nil {
  1046  		t.Fatalf("Couldn't create cacher: %v", err)
  1047  	}
  1048  	defer cacher.Stop()
  1049  
  1050  	// Ensure that bookmarks are sent more frequently than every 1m.
  1051  	cacher.bookmarkWatchers = newTimeBucketWatchers(clock.RealClock{}, 2*time.Second)
  1052  
  1053  	// Wait until cacher is initialized.
  1054  	if err := cacher.ready.wait(context.Background()); err != nil {
  1055  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1056  	}
  1057  
  1058  	makePod := func(i int) *examplev1.Pod {
  1059  		return &examplev1.Pod{
  1060  			ObjectMeta: metav1.ObjectMeta{
  1061  				Name:            fmt.Sprintf("pod-%d", i),
  1062  				Namespace:       "ns",
  1063  				ResourceVersion: fmt.Sprintf("%d", i),
  1064  			},
  1065  		}
  1066  	}
  1067  	if err := cacher.watchCache.Add(makePod(1000)); err != nil {
  1068  		t.Errorf("error: %v", err)
  1069  	}
  1070  
  1071  	pred := storage.Everything
  1072  	pred.AllowWatchBookmarks = true
  1073  
  1074  	w, err := cacher.Watch(context.TODO(), "/pods/ns", storage.ListOptions{
  1075  		ResourceVersion: "1000",
  1076  		Predicate:       pred,
  1077  	})
  1078  	if err != nil {
  1079  		t.Fatalf("Failed to create watch: %v", err)
  1080  	}
  1081  
  1082  	expectedRV := 2000
  1083  
  1084  	var rcErr error
  1085  
  1086  	wg := sync.WaitGroup{}
  1087  	wg.Add(1)
  1088  	go func() {
  1089  		defer wg.Done()
  1090  		for {
  1091  			event, ok := <-w.ResultChan()
  1092  			if !ok {
  1093  				rcErr = errors.New("Unexpected closed channel")
  1094  				return
  1095  			}
  1096  			rv, err := cacher.versioner.ObjectResourceVersion(event.Object)
  1097  			if err != nil {
  1098  				t.Errorf("failed to parse resource version from %#v: %v", event.Object, err)
  1099  			}
  1100  			if event.Type == watch.Bookmark && rv == uint64(expectedRV) {
  1101  				return
  1102  			}
  1103  		}
  1104  	}()
  1105  
  1106  	// Simulate progress notify event.
  1107  	cacher.watchCache.UpdateResourceVersion(strconv.Itoa(expectedRV))
  1108  
  1109  	wg.Wait()
  1110  	if rcErr != nil {
  1111  		t.Fatal(rcErr)
  1112  	}
  1113  }
  1114  
  1115  type fakeTimeBudget struct{}
  1116  
  1117  func (f *fakeTimeBudget) takeAvailable() time.Duration {
  1118  	return 2 * time.Second
  1119  }
  1120  
  1121  func (f *fakeTimeBudget) returnUnused(_ time.Duration) {}
  1122  
  1123  func TestStartingResourceVersion(t *testing.T) {
  1124  	backingStorage := &dummyStorage{}
  1125  	cacher, _, err := newTestCacher(backingStorage)
  1126  	if err != nil {
  1127  		t.Fatalf("Couldn't create cacher: %v", err)
  1128  	}
  1129  	defer cacher.Stop()
  1130  
  1131  	// Wait until cacher is initialized.
  1132  	if err := cacher.ready.wait(context.Background()); err != nil {
  1133  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1134  	}
  1135  
  1136  	// Ensure there is some budget for slowing down processing.
  1137  	// We use the fakeTimeBudget to prevent this test from flaking under
  1138  	// the following conditions:
  1139  	// 1) in total we create 11 events that has to be processed by the watcher
  1140  	// 2) the size of the channels are set to 10 for the watcher
  1141  	// 3) if the test is cpu-starved and the internal goroutine is not picking
  1142  	//    up these events from the channel, after consuming the whole time
  1143  	//    budget (defaulted to 100ms) on waiting, we will simply close the watch,
  1144  	//    which will cause the test failure
  1145  	// Using fakeTimeBudget gives us always a budget to wait and have a test
  1146  	// pick up something from ResultCh in the meantime.
  1147  	//
  1148  	// The same can potentially happen in production, but in that case a watch
  1149  	// can be resumed by the client. This doesn't work in the case of this test,
  1150  	// because we explicitly want to test the behavior that object changes are
  1151  	// happening after the watch was initiated.
  1152  	cacher.dispatchTimeoutBudget = &fakeTimeBudget{}
  1153  
  1154  	makePod := func(i int) *examplev1.Pod {
  1155  		return &examplev1.Pod{
  1156  			ObjectMeta: metav1.ObjectMeta{
  1157  				Name:            "foo",
  1158  				Namespace:       "ns",
  1159  				Labels:          map[string]string{"foo": strconv.Itoa(i)},
  1160  				ResourceVersion: fmt.Sprintf("%d", i),
  1161  			},
  1162  		}
  1163  	}
  1164  
  1165  	if err := cacher.watchCache.Add(makePod(1000)); err != nil {
  1166  		t.Errorf("error: %v", err)
  1167  	}
  1168  	// Advance RV by 10.
  1169  	startVersion := uint64(1010)
  1170  
  1171  	watcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", storage.ListOptions{ResourceVersion: strconv.FormatUint(startVersion, 10), Predicate: storage.Everything})
  1172  	if err != nil {
  1173  		t.Fatalf("Unexpected error: %v", err)
  1174  	}
  1175  	defer watcher.Stop()
  1176  
  1177  	for i := 1; i <= 11; i++ {
  1178  		if err := cacher.watchCache.Update(makePod(1000 + i)); err != nil {
  1179  			t.Errorf("error: %v", err)
  1180  		}
  1181  	}
  1182  
  1183  	e, ok := <-watcher.ResultChan()
  1184  	if !ok {
  1185  		t.Errorf("unexpectedly closed watch")
  1186  	}
  1187  	object := e.Object
  1188  	if co, ok := object.(runtime.CacheableObject); ok {
  1189  		object = co.GetObject()
  1190  	}
  1191  	pod := object.(*examplev1.Pod)
  1192  	podRV, err := cacher.versioner.ParseResourceVersion(pod.ResourceVersion)
  1193  	if err != nil {
  1194  		t.Fatalf("unexpected error: %v", err)
  1195  	}
  1196  
  1197  	// event should have at least rv + 1, since we're starting the watch at rv
  1198  	if podRV <= startVersion {
  1199  		t.Errorf("expected event with resourceVersion of at least %d, got %d", startVersion+1, podRV)
  1200  	}
  1201  }
  1202  
  1203  func TestDispatchEventWillNotBeBlockedByTimedOutWatcher(t *testing.T) {
  1204  	backingStorage := &dummyStorage{}
  1205  	cacher, _, err := newTestCacher(backingStorage)
  1206  	if err != nil {
  1207  		t.Fatalf("Couldn't create cacher: %v", err)
  1208  	}
  1209  	defer cacher.Stop()
  1210  
  1211  	// Wait until cacher is initialized.
  1212  	if err := cacher.ready.wait(context.Background()); err != nil {
  1213  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1214  	}
  1215  
  1216  	// Ensure there is some budget for slowing down processing.
  1217  	// We use the fakeTimeBudget to prevent this test from flaking under
  1218  	// the following conditions:
  1219  	// 1) the watch w1 is blocked, so we were consuming the whole budget once
  1220  	//    its buffer was filled in (10 items)
  1221  	// 2) the budget is refreshed once per second, so it basically wasn't
  1222  	//    happening in the test at all
  1223  	// 3) if the test was cpu-starved and we weren't able to consume events
  1224  	//    from w2 ResultCh it could have happened that its buffer was also
  1225  	//    filling in and given we no longer had timeBudget (consumed in (1))
  1226  	//    trying to put next item was simply breaking the watch
  1227  	// Using fakeTimeBudget gives us always a budget to wait and have a test
  1228  	// pick up something from ResultCh in the meantime.
  1229  	cacher.dispatchTimeoutBudget = &fakeTimeBudget{}
  1230  
  1231  	makePod := func(i int) *examplev1.Pod {
  1232  		return &examplev1.Pod{
  1233  			ObjectMeta: metav1.ObjectMeta{
  1234  				Name:            fmt.Sprintf("pod-%d", 1000+i),
  1235  				Namespace:       "ns",
  1236  				ResourceVersion: fmt.Sprintf("%d", 1000+i),
  1237  			},
  1238  		}
  1239  	}
  1240  	if err := cacher.watchCache.Add(makePod(0)); err != nil {
  1241  		t.Errorf("error: %v", err)
  1242  	}
  1243  
  1244  	totalPods := 50
  1245  
  1246  	// Create watcher that will be blocked.
  1247  	w1, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{ResourceVersion: "999", Predicate: storage.Everything})
  1248  	if err != nil {
  1249  		t.Fatalf("Failed to create watch: %v", err)
  1250  	}
  1251  	defer w1.Stop()
  1252  
  1253  	// Create fast watcher and ensure it will get all objects.
  1254  	w2, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{ResourceVersion: "999", Predicate: storage.Everything})
  1255  	if err != nil {
  1256  		t.Fatalf("Failed to create watch: %v", err)
  1257  	}
  1258  	defer w2.Stop()
  1259  
  1260  	// Now push a ton of object to cache.
  1261  	for i := 1; i < totalPods; i++ {
  1262  		cacher.watchCache.Add(makePod(i))
  1263  	}
  1264  
  1265  	shouldContinue := true
  1266  	eventsCount := 0
  1267  	for shouldContinue {
  1268  		select {
  1269  		case event, ok := <-w2.ResultChan():
  1270  			if !ok {
  1271  				shouldContinue = false
  1272  				break
  1273  			}
  1274  			if event.Type == watch.Added {
  1275  				eventsCount++
  1276  				if eventsCount == totalPods {
  1277  					shouldContinue = false
  1278  				}
  1279  			}
  1280  		case <-time.After(wait.ForeverTestTimeout):
  1281  			shouldContinue = false
  1282  			w2.Stop()
  1283  		}
  1284  	}
  1285  	if eventsCount != totalPods {
  1286  		t.Errorf("watcher is blocked by slower one (count: %d)", eventsCount)
  1287  	}
  1288  }
  1289  
  1290  func verifyEvents(t *testing.T, w watch.Interface, events []watch.Event, strictOrder bool) {
  1291  	_, _, line, _ := goruntime.Caller(1)
  1292  	actualEvents := make([]watch.Event, len(events))
  1293  	for idx := range events {
  1294  		select {
  1295  		case event := <-w.ResultChan():
  1296  			actualEvents[idx] = event
  1297  		case <-time.After(wait.ForeverTestTimeout):
  1298  			t.Logf("(called from line %d)", line)
  1299  			t.Errorf("Timed out waiting for an event")
  1300  		}
  1301  	}
  1302  	validateEvents := func(expected, actual watch.Event) (bool, []string) {
  1303  		errors := []string{}
  1304  		if e, a := expected.Type, actual.Type; e != a {
  1305  			errors = append(errors, fmt.Sprintf("Expected: %s, got: %s", e, a))
  1306  		}
  1307  		actualObject := actual.Object
  1308  		if co, ok := actualObject.(runtime.CacheableObject); ok {
  1309  			actualObject = co.GetObject()
  1310  		}
  1311  		if e, a := expected.Object, actualObject; !apiequality.Semantic.DeepEqual(e, a) {
  1312  			errors = append(errors, fmt.Sprintf("Expected: %#v, got: %#v", e, a))
  1313  		}
  1314  		return len(errors) == 0, errors
  1315  	}
  1316  
  1317  	if len(events) != len(actualEvents) {
  1318  		t.Fatalf("unexpected number of events: %d, expected: %d, acutalEvents: %#v, expectedEvents:%#v", len(actualEvents), len(events), actualEvents, events)
  1319  	}
  1320  
  1321  	if strictOrder {
  1322  		for idx, expectedEvent := range events {
  1323  			valid, errors := validateEvents(expectedEvent, actualEvents[idx])
  1324  			if !valid {
  1325  				t.Logf("(called from line %d)", line)
  1326  				for _, err := range errors {
  1327  					t.Errorf(err)
  1328  				}
  1329  			}
  1330  		}
  1331  	}
  1332  	for _, expectedEvent := range events {
  1333  		validated := false
  1334  		for _, actualEvent := range actualEvents {
  1335  			if validated, _ = validateEvents(expectedEvent, actualEvent); validated {
  1336  				break
  1337  			}
  1338  		}
  1339  		if !validated {
  1340  			t.Fatalf("Expected: %#v but didn't find", expectedEvent)
  1341  		}
  1342  	}
  1343  }
  1344  
  1345  func TestCachingDeleteEvents(t *testing.T) {
  1346  	backingStorage := &dummyStorage{}
  1347  	cacher, _, err := newTestCacher(backingStorage)
  1348  	if err != nil {
  1349  		t.Fatalf("Couldn't create cacher: %v", err)
  1350  	}
  1351  	defer cacher.Stop()
  1352  
  1353  	// Wait until cacher is initialized.
  1354  	if err := cacher.ready.wait(context.Background()); err != nil {
  1355  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1356  	}
  1357  
  1358  	fooPredicate := storage.SelectionPredicate{
  1359  		Label: labels.SelectorFromSet(map[string]string{"foo": "true"}),
  1360  		Field: fields.Everything(),
  1361  	}
  1362  	barPredicate := storage.SelectionPredicate{
  1363  		Label: labels.SelectorFromSet(map[string]string{"bar": "true"}),
  1364  		Field: fields.Everything(),
  1365  	}
  1366  
  1367  	createWatch := func(pred storage.SelectionPredicate) watch.Interface {
  1368  		w, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{ResourceVersion: "999", Predicate: pred})
  1369  		if err != nil {
  1370  			t.Fatalf("Failed to create watch: %v", err)
  1371  		}
  1372  		return w
  1373  	}
  1374  
  1375  	allEventsWatcher := createWatch(storage.Everything)
  1376  	defer allEventsWatcher.Stop()
  1377  	fooEventsWatcher := createWatch(fooPredicate)
  1378  	defer fooEventsWatcher.Stop()
  1379  	barEventsWatcher := createWatch(barPredicate)
  1380  	defer barEventsWatcher.Stop()
  1381  
  1382  	makePod := func(labels map[string]string, rv string) *examplev1.Pod {
  1383  		return &examplev1.Pod{
  1384  			ObjectMeta: metav1.ObjectMeta{
  1385  				Name:            "pod",
  1386  				Namespace:       "ns",
  1387  				Labels:          labels,
  1388  				ResourceVersion: rv,
  1389  			},
  1390  		}
  1391  	}
  1392  	pod1 := makePod(map[string]string{"foo": "true", "bar": "true"}, "1001")
  1393  	pod2 := makePod(map[string]string{"foo": "true"}, "1002")
  1394  	pod3 := makePod(map[string]string{}, "1003")
  1395  	pod4 := makePod(map[string]string{}, "1004")
  1396  	pod1DeletedAt2 := pod1.DeepCopyObject().(*examplev1.Pod)
  1397  	pod1DeletedAt2.ResourceVersion = "1002"
  1398  	pod2DeletedAt3 := pod2.DeepCopyObject().(*examplev1.Pod)
  1399  	pod2DeletedAt3.ResourceVersion = "1003"
  1400  
  1401  	allEvents := []watch.Event{
  1402  		{Type: watch.Added, Object: pod1.DeepCopy()},
  1403  		{Type: watch.Modified, Object: pod2.DeepCopy()},
  1404  		{Type: watch.Modified, Object: pod3.DeepCopy()},
  1405  		{Type: watch.Deleted, Object: pod4.DeepCopy()},
  1406  	}
  1407  	fooEvents := []watch.Event{
  1408  		{Type: watch.Added, Object: pod1.DeepCopy()},
  1409  		{Type: watch.Modified, Object: pod2.DeepCopy()},
  1410  		{Type: watch.Deleted, Object: pod2DeletedAt3.DeepCopy()},
  1411  	}
  1412  	barEvents := []watch.Event{
  1413  		{Type: watch.Added, Object: pod1.DeepCopy()},
  1414  		{Type: watch.Deleted, Object: pod1DeletedAt2.DeepCopy()},
  1415  	}
  1416  
  1417  	cacher.watchCache.Add(pod1)
  1418  	cacher.watchCache.Update(pod2)
  1419  	cacher.watchCache.Update(pod3)
  1420  	cacher.watchCache.Delete(pod4)
  1421  
  1422  	verifyEvents(t, allEventsWatcher, allEvents, true)
  1423  	verifyEvents(t, fooEventsWatcher, fooEvents, true)
  1424  	verifyEvents(t, barEventsWatcher, barEvents, true)
  1425  }
  1426  
  1427  func testCachingObjects(t *testing.T, watchersCount int) {
  1428  	backingStorage := &dummyStorage{}
  1429  	cacher, _, err := newTestCacher(backingStorage)
  1430  	if err != nil {
  1431  		t.Fatalf("Couldn't create cacher: %v", err)
  1432  	}
  1433  	defer cacher.Stop()
  1434  
  1435  	// Wait until cacher is initialized.
  1436  	if err := cacher.ready.wait(context.Background()); err != nil {
  1437  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1438  	}
  1439  
  1440  	dispatchedEvents := []*watchCacheEvent{}
  1441  	cacher.watchCache.eventHandler = func(event *watchCacheEvent) {
  1442  		dispatchedEvents = append(dispatchedEvents, event)
  1443  		cacher.processEvent(event)
  1444  	}
  1445  
  1446  	watchers := make([]watch.Interface, 0, watchersCount)
  1447  	for i := 0; i < watchersCount; i++ {
  1448  		w, err := cacher.Watch(context.TODO(), "pods/ns", storage.ListOptions{ResourceVersion: "1000", Predicate: storage.Everything})
  1449  		if err != nil {
  1450  			t.Fatalf("Failed to create watch: %v", err)
  1451  		}
  1452  		defer w.Stop()
  1453  		watchers = append(watchers, w)
  1454  	}
  1455  
  1456  	makePod := func(name, rv string) *examplev1.Pod {
  1457  		return &examplev1.Pod{
  1458  			ObjectMeta: metav1.ObjectMeta{
  1459  				Name:            name,
  1460  				Namespace:       "ns",
  1461  				ResourceVersion: rv,
  1462  			},
  1463  		}
  1464  	}
  1465  	pod1 := makePod("pod", "1001")
  1466  	pod2 := makePod("pod", "1002")
  1467  	pod3 := makePod("pod", "1003")
  1468  
  1469  	cacher.watchCache.Add(pod1)
  1470  	cacher.watchCache.Update(pod2)
  1471  	cacher.watchCache.Delete(pod3)
  1472  
  1473  	// At this point, we already have dispatchedEvents fully propagated.
  1474  
  1475  	verifyEvents := func(w watch.Interface) {
  1476  		var event watch.Event
  1477  		for index := range dispatchedEvents {
  1478  			select {
  1479  			case event = <-w.ResultChan():
  1480  			case <-time.After(wait.ForeverTestTimeout):
  1481  				t.Fatalf("timeout watiching for the event")
  1482  			}
  1483  
  1484  			var object runtime.Object
  1485  			if _, ok := event.Object.(runtime.CacheableObject); !ok {
  1486  				t.Fatalf("Object in %s event should support caching: %#v", event.Type, event.Object)
  1487  			}
  1488  			object = event.Object.(runtime.CacheableObject).GetObject()
  1489  
  1490  			if event.Type == watch.Deleted {
  1491  				resourceVersion, err := cacher.versioner.ObjectResourceVersion(cacher.watchCache.cache[index].PrevObject)
  1492  				if err != nil {
  1493  					t.Fatalf("Failed to parse resource version: %v", err)
  1494  				}
  1495  				updateResourceVersion(object, cacher.versioner, resourceVersion)
  1496  			}
  1497  
  1498  			var e runtime.Object
  1499  			switch event.Type {
  1500  			case watch.Added, watch.Modified:
  1501  				e = cacher.watchCache.cache[index].Object
  1502  			case watch.Deleted:
  1503  				e = cacher.watchCache.cache[index].PrevObject
  1504  			default:
  1505  				t.Errorf("unexpected watch event: %#v", event)
  1506  			}
  1507  			if a := object; !reflect.DeepEqual(a, e) {
  1508  				t.Errorf("event object messed up for %s: %#v, expected: %#v", event.Type, a, e)
  1509  			}
  1510  		}
  1511  	}
  1512  
  1513  	for i := range watchers {
  1514  		verifyEvents(watchers[i])
  1515  	}
  1516  }
  1517  
  1518  func TestCachingObjects(t *testing.T) {
  1519  	t.Run("single watcher", func(t *testing.T) { testCachingObjects(t, 1) })
  1520  	t.Run("many watcher", func(t *testing.T) { testCachingObjects(t, 3) })
  1521  }
  1522  
  1523  func TestCacheIntervalInvalidationStopsWatch(t *testing.T) {
  1524  	backingStorage := &dummyStorage{}
  1525  	cacher, _, err := newTestCacher(backingStorage)
  1526  	if err != nil {
  1527  		t.Fatalf("Couldn't create cacher: %v", err)
  1528  	}
  1529  	defer cacher.Stop()
  1530  
  1531  	// Wait until cacher is initialized.
  1532  	if err := cacher.ready.wait(context.Background()); err != nil {
  1533  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1534  	}
  1535  	// Ensure there is enough budget for slow processing since
  1536  	// the entire watch cache is going to be served through the
  1537  	// interval and events won't be popped from the cacheWatcher's
  1538  	// input channel until much later.
  1539  	cacher.dispatchTimeoutBudget.returnUnused(100 * time.Millisecond)
  1540  
  1541  	// We define a custom index validator such that the interval is
  1542  	// able to serve the first bufferSize elements successfully, but
  1543  	// on trying to fill it's buffer again, the indexValidator simulates
  1544  	// an invalidation leading to the watch being closed and the number
  1545  	// of events we actually process to be bufferSize, each event of
  1546  	// type watch.Added.
  1547  	valid := true
  1548  	invalidateCacheInterval := func() {
  1549  		valid = false
  1550  	}
  1551  	once := sync.Once{}
  1552  	indexValidator := func(index int) bool {
  1553  		isValid := valid && (index >= cacher.watchCache.startIndex)
  1554  		once.Do(invalidateCacheInterval)
  1555  		return isValid
  1556  	}
  1557  	cacher.watchCache.indexValidator = indexValidator
  1558  
  1559  	makePod := func(i int) *examplev1.Pod {
  1560  		return &examplev1.Pod{
  1561  			ObjectMeta: metav1.ObjectMeta{
  1562  				Name:            fmt.Sprintf("pod-%d", 1000+i),
  1563  				Namespace:       "ns",
  1564  				ResourceVersion: fmt.Sprintf("%d", 1000+i),
  1565  			},
  1566  		}
  1567  	}
  1568  
  1569  	// 250 is arbitrary, point is to have enough elements such that
  1570  	// it generates more than bufferSize number of events allowing
  1571  	// us to simulate the invalidation of the cache interval.
  1572  	totalPods := 250
  1573  	for i := 0; i < totalPods; i++ {
  1574  		err := cacher.watchCache.Add(makePod(i))
  1575  		if err != nil {
  1576  			t.Errorf("error: %v", err)
  1577  		}
  1578  	}
  1579  	ctx, cancel := context.WithCancel(context.Background())
  1580  	defer cancel()
  1581  
  1582  	w, err := cacher.Watch(ctx, "pods/ns", storage.ListOptions{
  1583  		ResourceVersion: "999",
  1584  		Predicate:       storage.Everything,
  1585  	})
  1586  	if err != nil {
  1587  		t.Fatalf("Failed to create watch: %v", err)
  1588  	}
  1589  	defer w.Stop()
  1590  
  1591  	received := 0
  1592  	resChan := w.ResultChan()
  1593  	for event := range resChan {
  1594  		received++
  1595  		t.Logf("event type: %v, events received so far: %d", event.Type, received)
  1596  		if event.Type != watch.Added {
  1597  			t.Errorf("unexpected event type, expected: %s, got: %s, event: %v", watch.Added, event.Type, event)
  1598  		}
  1599  	}
  1600  	// Since the watch is stopped after the interval is invalidated,
  1601  	// we should have processed exactly bufferSize number of elements.
  1602  	if received != bufferSize {
  1603  		t.Errorf("unexpected number of events received, expected: %d, got: %d", bufferSize+1, received)
  1604  	}
  1605  }
  1606  
  1607  func TestWaitUntilWatchCacheFreshAndForceAllEvents(t *testing.T) {
  1608  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WatchList, true)()
  1609  	backingStorage := &dummyStorage{}
  1610  	cacher, _, err := newTestCacher(backingStorage)
  1611  	if err != nil {
  1612  		t.Fatalf("Couldn't create cacher: %v", err)
  1613  	}
  1614  	defer cacher.Stop()
  1615  
  1616  	opts := storage.ListOptions{
  1617  		Predicate:         storage.Everything,
  1618  		SendInitialEvents: pointer.Bool(true),
  1619  		ResourceVersion:   "105",
  1620  	}
  1621  	opts.Predicate.AllowWatchBookmarks = true
  1622  
  1623  	w, err := cacher.Watch(context.Background(), "pods/ns", opts)
  1624  	require.NoError(t, err, "failed to create watch: %v")
  1625  	defer w.Stop()
  1626  	verifyEvents(t, w, []watch.Event{
  1627  		{
  1628  			Type: watch.Error,
  1629  			Object: &metav1.Status{
  1630  				Status:  metav1.StatusFailure,
  1631  				Message: storage.NewTooLargeResourceVersionError(105, 100, resourceVersionTooHighRetrySeconds).Error(),
  1632  				Details: storage.NewTooLargeResourceVersionError(105, 100, resourceVersionTooHighRetrySeconds).(*apierrors.StatusError).Status().Details,
  1633  				Reason:  metav1.StatusReasonTimeout,
  1634  				Code:    504,
  1635  			},
  1636  		},
  1637  	}, true)
  1638  
  1639  	go func() {
  1640  		cacher.watchCache.Add(makeTestPodDetails("pod1", 105, "node1", map[string]string{"label": "value1"}))
  1641  	}()
  1642  	w, err = cacher.Watch(context.Background(), "pods/ns", opts)
  1643  	require.NoError(t, err, "failed to create watch: %v")
  1644  	defer w.Stop()
  1645  	verifyEvents(t, w, []watch.Event{
  1646  		{
  1647  			Type:   watch.Added,
  1648  			Object: makeTestPodDetails("pod1", 105, "node1", map[string]string{"label": "value1"}),
  1649  		},
  1650  	}, true)
  1651  }
  1652  
  1653  type fakeStorage struct {
  1654  	pods []example.Pod
  1655  	storage.Interface
  1656  }
  1657  
  1658  func newObjectStorage(fakePods []example.Pod) *fakeStorage {
  1659  	return &fakeStorage{
  1660  		pods: fakePods,
  1661  	}
  1662  }
  1663  
  1664  func (m fakeStorage) GetList(ctx context.Context, key string, opts storage.ListOptions, listObj runtime.Object) error {
  1665  	podList := listObj.(*example.PodList)
  1666  	podList.ListMeta = metav1.ListMeta{ResourceVersion: "12345"}
  1667  	podList.Items = m.pods
  1668  	return nil
  1669  }
  1670  func (m fakeStorage) Watch(_ context.Context, _ string, _ storage.ListOptions) (watch.Interface, error) {
  1671  	return newDummyWatch(), nil
  1672  }
  1673  
  1674  func BenchmarkCacher_GetList(b *testing.B) {
  1675  	testCases := []struct {
  1676  		totalObjectNum  int
  1677  		expectObjectNum int
  1678  	}{
  1679  		{
  1680  			totalObjectNum:  5000,
  1681  			expectObjectNum: 50,
  1682  		},
  1683  		{
  1684  			totalObjectNum:  5000,
  1685  			expectObjectNum: 500,
  1686  		},
  1687  		{
  1688  			totalObjectNum:  5000,
  1689  			expectObjectNum: 1000,
  1690  		},
  1691  		{
  1692  			totalObjectNum:  5000,
  1693  			expectObjectNum: 2500,
  1694  		},
  1695  		{
  1696  			totalObjectNum:  5000,
  1697  			expectObjectNum: 5000,
  1698  		},
  1699  	}
  1700  	for _, tc := range testCases {
  1701  		b.Run(
  1702  			fmt.Sprintf("totalObjectNum=%d, expectObjectNum=%d", tc.totalObjectNum, tc.expectObjectNum),
  1703  			func(b *testing.B) {
  1704  				// create sample pods
  1705  				fakePods := make([]example.Pod, tc.totalObjectNum, tc.totalObjectNum)
  1706  				for i := range fakePods {
  1707  					fakePods[i].Namespace = "default"
  1708  					fakePods[i].Name = fmt.Sprintf("pod-%d", i)
  1709  					fakePods[i].ResourceVersion = strconv.Itoa(i)
  1710  					if i%(tc.totalObjectNum/tc.expectObjectNum) == 0 {
  1711  						fakePods[i].Spec.NodeName = "node-0"
  1712  					}
  1713  					data := make([]byte, 1024*2, 1024*2) // 2k labels
  1714  					rand.Read(data)
  1715  					fakePods[i].Spec.NodeSelector = map[string]string{
  1716  						"key": string(data),
  1717  					}
  1718  				}
  1719  
  1720  				// build test cacher
  1721  				cacher, _, err := newTestCacher(newObjectStorage(fakePods))
  1722  				if err != nil {
  1723  					b.Fatalf("new cacher: %v", err)
  1724  				}
  1725  				defer cacher.Stop()
  1726  
  1727  				// prepare result and pred
  1728  				parsedField, err := fields.ParseSelector("spec.nodeName=node-0")
  1729  				if err != nil {
  1730  					b.Fatalf("parse selector: %v", err)
  1731  				}
  1732  				pred := storage.SelectionPredicate{
  1733  					Label: labels.Everything(),
  1734  					Field: parsedField,
  1735  				}
  1736  
  1737  				// now we start benchmarking
  1738  				b.ResetTimer()
  1739  				for i := 0; i < b.N; i++ {
  1740  					result := &example.PodList{}
  1741  					err = cacher.GetList(context.TODO(), "pods", storage.ListOptions{
  1742  						Predicate:       pred,
  1743  						Recursive:       true,
  1744  						ResourceVersion: "12345",
  1745  					}, result)
  1746  					if err != nil {
  1747  						b.Fatalf("GetList cache: %v", err)
  1748  					}
  1749  					if len(result.Items) != tc.expectObjectNum {
  1750  						b.Fatalf("expect %d but got %d", tc.expectObjectNum, len(result.Items))
  1751  					}
  1752  				}
  1753  			})
  1754  	}
  1755  }
  1756  
  1757  // TestDoNotPopExpiredWatchersWhenNoEventsSeen makes sure that
  1758  // a bookmark event will be delivered after the cacher has seen an event.
  1759  // Previously the watchers have been removed from the "want bookmark" queue.
  1760  func TestDoNotPopExpiredWatchersWhenNoEventsSeen(t *testing.T) {
  1761  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WatchList, true)()
  1762  	backingStorage := &dummyStorage{}
  1763  	cacher, _, err := newTestCacher(backingStorage)
  1764  	if err != nil {
  1765  		t.Fatalf("Couldn't create cacher: %v", err)
  1766  	}
  1767  	defer cacher.Stop()
  1768  
  1769  	// wait until cacher is initialized.
  1770  	if err := cacher.ready.wait(context.Background()); err != nil {
  1771  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1772  	}
  1773  
  1774  	pred := storage.Everything
  1775  	pred.AllowWatchBookmarks = true
  1776  	opts := storage.ListOptions{
  1777  		Predicate:         pred,
  1778  		SendInitialEvents: pointer.Bool(true),
  1779  	}
  1780  	w, err := cacher.Watch(context.Background(), "pods/ns", opts)
  1781  	require.NoError(t, err, "failed to create watch: %v")
  1782  	defer w.Stop()
  1783  
  1784  	// Ensure that popExpiredWatchers is called to ensure that our watch isn't removed from bookmarkWatchers.
  1785  	// We do that every ~1s, so waiting 2 seconds seems enough.
  1786  	time.Sleep(2 * time.Second)
  1787  
  1788  	// Send an event to ensure that lastProcessedResourceVersion in Cacher will change to non-zero value.
  1789  	makePod := func(rv uint64) *example.Pod {
  1790  		return &example.Pod{
  1791  			ObjectMeta: metav1.ObjectMeta{
  1792  				Name:            fmt.Sprintf("pod-%d", rv),
  1793  				Namespace:       "ns",
  1794  				ResourceVersion: fmt.Sprintf("%d", rv),
  1795  				Annotations:     map[string]string{},
  1796  			},
  1797  		}
  1798  	}
  1799  	err = cacher.watchCache.Add(makePod(102))
  1800  	require.NoError(t, err)
  1801  
  1802  	verifyEvents(t, w, []watch.Event{
  1803  		{Type: watch.Added, Object: makePod(102)},
  1804  		{Type: watch.Bookmark, Object: &example.Pod{
  1805  			ObjectMeta: metav1.ObjectMeta{
  1806  				ResourceVersion: "102",
  1807  				Annotations:     map[string]string{"k8s.io/initial-events-end": "true"},
  1808  			},
  1809  		}},
  1810  	}, true)
  1811  }
  1812  
  1813  func TestForgetWatcher(t *testing.T) {
  1814  	backingStorage := &dummyStorage{}
  1815  	cacher, _, err := newTestCacher(backingStorage)
  1816  	require.NoError(t, err)
  1817  	defer cacher.Stop()
  1818  
  1819  	// wait until cacher is initialized.
  1820  	if err := cacher.ready.wait(context.Background()); err != nil {
  1821  		t.Fatalf("unexpected error waiting for the cache to be ready")
  1822  	}
  1823  
  1824  	assertCacherInternalState := func(expectedWatchersCounter, expectedValueWatchersCounter int) {
  1825  		cacher.Lock()
  1826  		defer cacher.Unlock()
  1827  
  1828  		require.Equal(t, expectedWatchersCounter, len(cacher.watchers.allWatchers))
  1829  		require.Equal(t, expectedValueWatchersCounter, len(cacher.watchers.valueWatchers))
  1830  	}
  1831  	assertCacherInternalState(0, 0)
  1832  
  1833  	var forgetWatcherFn func(bool)
  1834  	var forgetCounter int
  1835  	forgetWatcherWrapped := func(drainWatcher bool) {
  1836  		forgetCounter++
  1837  		forgetWatcherFn(drainWatcher)
  1838  	}
  1839  	w := newCacheWatcher(
  1840  		0,
  1841  		func(_ string, _ labels.Set, _ fields.Set) bool { return true },
  1842  		nil,
  1843  		storage.APIObjectVersioner{},
  1844  		testingclock.NewFakeClock(time.Now()).Now().Add(2*time.Minute),
  1845  		true,
  1846  		schema.GroupResource{Resource: "pods"},
  1847  		"1",
  1848  	)
  1849  	forgetWatcherFn = forgetWatcher(cacher, w, 0, namespacedName{}, "", false)
  1850  	addWatcher := func(w *cacheWatcher) {
  1851  		cacher.Lock()
  1852  		defer cacher.Unlock()
  1853  
  1854  		cacher.watchers.addWatcher(w, 0, namespacedName{}, "", false)
  1855  	}
  1856  
  1857  	addWatcher(w)
  1858  	assertCacherInternalState(1, 0)
  1859  
  1860  	forgetWatcherWrapped(false)
  1861  	assertCacherInternalState(0, 0)
  1862  	require.Equal(t, 1, forgetCounter)
  1863  
  1864  	forgetWatcherWrapped(false)
  1865  	assertCacherInternalState(0, 0)
  1866  	require.Equal(t, 2, forgetCounter)
  1867  }
  1868  
  1869  func TestWatchStreamSeparation(t *testing.T) {
  1870  	tcs := []struct {
  1871  		name                         string
  1872  		separateCacheWatchRPC        bool
  1873  		useWatchCacheContextMetadata bool
  1874  		expectBookmarkOnWatchCache   bool
  1875  		expectBookmarkOnEtcd         bool
  1876  	}{
  1877  		{
  1878  			name:                       "common RPC > both get bookmarks",
  1879  			separateCacheWatchRPC:      false,
  1880  			expectBookmarkOnEtcd:       true,
  1881  			expectBookmarkOnWatchCache: true,
  1882  		},
  1883  		{
  1884  			name:                         "common RPC & watch cache context > both get bookmarks",
  1885  			separateCacheWatchRPC:        false,
  1886  			useWatchCacheContextMetadata: true,
  1887  			expectBookmarkOnEtcd:         true,
  1888  			expectBookmarkOnWatchCache:   true,
  1889  		},
  1890  		{
  1891  			name:                       "separate RPC > only etcd gets bookmarks",
  1892  			separateCacheWatchRPC:      true,
  1893  			expectBookmarkOnEtcd:       true,
  1894  			expectBookmarkOnWatchCache: false,
  1895  		},
  1896  		{
  1897  			name:                         "separate RPC & watch cache context > only watch cache gets bookmarks",
  1898  			separateCacheWatchRPC:        true,
  1899  			useWatchCacheContextMetadata: true,
  1900  			expectBookmarkOnEtcd:         false,
  1901  			expectBookmarkOnWatchCache:   true,
  1902  		},
  1903  	}
  1904  	for _, tc := range tcs {
  1905  		t.Run(tc.name, func(t *testing.T) {
  1906  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SeparateCacheWatchRPC, tc.separateCacheWatchRPC)()
  1907  			_, cacher, _, terminate := testSetupWithEtcdServer(t)
  1908  			t.Cleanup(terminate)
  1909  			if err := cacher.ready.wait(context.TODO()); err != nil {
  1910  				t.Fatalf("unexpected error waiting for the cache to be ready")
  1911  			}
  1912  
  1913  			getCacherRV := func() uint64 {
  1914  				cacher.watchCache.RLock()
  1915  				defer cacher.watchCache.RUnlock()
  1916  				return cacher.watchCache.resourceVersion
  1917  			}
  1918  			waitContext, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  1919  			defer cancel()
  1920  			waitForEtcdBookmark := watchAndWaitForBookmark(t, waitContext, cacher.storage)
  1921  
  1922  			var out example.Pod
  1923  			err := cacher.Create(context.Background(), "foo", &example.Pod{}, &out, 0)
  1924  			if err != nil {
  1925  				t.Fatal(err)
  1926  			}
  1927  			versioner := storage.APIObjectVersioner{}
  1928  			var lastResourceVersion uint64
  1929  			lastResourceVersion, err = versioner.ObjectResourceVersion(&out)
  1930  			if err != nil {
  1931  				t.Fatal(err)
  1932  			}
  1933  
  1934  			var contextMetadata metadata.MD
  1935  			if tc.useWatchCacheContextMetadata {
  1936  				contextMetadata = cacher.watchCache.waitingUntilFresh.contextMetadata
  1937  			}
  1938  			// Wait before sending watch progress request to avoid https://github.com/etcd-io/etcd/issues/17507
  1939  			// TODO(https://github.com/etcd-io/etcd/issues/17507): Remove sleep when etcd is upgraded to version with fix.
  1940  			time.Sleep(time.Second)
  1941  			err = cacher.storage.RequestWatchProgress(metadata.NewOutgoingContext(context.Background(), contextMetadata))
  1942  			if err != nil {
  1943  				t.Fatal(err)
  1944  			}
  1945  			// Give time for bookmark to arrive
  1946  			time.Sleep(time.Second)
  1947  
  1948  			etcdWatchResourceVersion := waitForEtcdBookmark()
  1949  			gotEtcdWatchBookmark := etcdWatchResourceVersion == lastResourceVersion
  1950  			if gotEtcdWatchBookmark != tc.expectBookmarkOnEtcd {
  1951  				t.Errorf("Unexpected etcd bookmark check result, rv: %d, got: %v, want: %v", etcdWatchResourceVersion, etcdWatchResourceVersion, tc.expectBookmarkOnEtcd)
  1952  			}
  1953  
  1954  			watchCacheResourceVersion := getCacherRV()
  1955  			cacherGotBookmark := watchCacheResourceVersion == lastResourceVersion
  1956  			if cacherGotBookmark != tc.expectBookmarkOnWatchCache {
  1957  				t.Errorf("Unexpected watch cache bookmark check result, rv: %d, got: %v, want: %v", watchCacheResourceVersion, cacherGotBookmark, tc.expectBookmarkOnWatchCache)
  1958  			}
  1959  		})
  1960  	}
  1961  }
  1962  
  1963  func watchAndWaitForBookmark(t *testing.T, ctx context.Context, etcdStorage storage.Interface) func() (resourceVersion uint64) {
  1964  	opts := storage.ListOptions{ResourceVersion: "", Predicate: storage.Everything, Recursive: true}
  1965  	opts.Predicate.AllowWatchBookmarks = true
  1966  	w, err := etcdStorage.Watch(ctx, "/pods/", opts)
  1967  	if err != nil {
  1968  		t.Fatal(err)
  1969  	}
  1970  
  1971  	versioner := storage.APIObjectVersioner{}
  1972  	var rv uint64
  1973  	var wg sync.WaitGroup
  1974  	wg.Add(1)
  1975  	go func() {
  1976  		defer wg.Done()
  1977  		for event := range w.ResultChan() {
  1978  			if event.Type == watch.Bookmark {
  1979  				rv, err = versioner.ObjectResourceVersion(event.Object)
  1980  				break
  1981  			}
  1982  		}
  1983  	}()
  1984  	return func() (resourceVersion uint64) {
  1985  		defer w.Stop()
  1986  		wg.Wait()
  1987  		if err != nil {
  1988  			t.Fatal(err)
  1989  		}
  1990  		return rv
  1991  	}
  1992  }