diff --git a/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_whitebox_test.go b/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_whitebox_test.go index 8d66bc77ce0..8a44802d86b 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_whitebox_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_whitebox_test.go @@ -1986,3 +1986,362 @@ func TestForgetWatcher(t *testing.T) { assertCacherInternalState(0, 0) require.Equal(t, 2, forgetCounter) } + +// TestGetWatchCacheResourceVersion test the following cases: +// +// +-----------------+---------------------+-----------------------+ +// | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | +// +=================+=====================+=======================+ +// | Unset | true/false | nil/true/false | +// | 0 | true/false | nil/true/false | +// | 95 | true/false | nil/true/false | +// +-----------------+---------------------+-----------------------+ +// where: +// - false indicates the value of the param was set to "false" by a test case +// - true indicates the value of the param was set to "true" by a test case +func TestGetWatchCacheResourceVersion(t *testing.T) { + listOptions := func(allowBookmarks bool, sendInitialEvents *bool, rv string) storage.ListOptions { + p := storage.Everything + p.AllowWatchBookmarks = allowBookmarks + + opts := storage.ListOptions{} + opts.Predicate = p + opts.SendInitialEvents = sendInitialEvents + opts.ResourceVersion = rv + return opts + } + + scenarios := []struct { + name string + opts storage.ListOptions + + expectedWatchResourceVersion int + }{ + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | Unset | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, ""), + expectedWatchResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), ""), + expectedWatchResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), ""), + expectedWatchResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, ""), + expectedWatchResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=true, legacy", + opts: listOptions(false, pointer.Bool(true), ""), + expectedWatchResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), ""), + expectedWatchResourceVersion: 100, + }, + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | 0 | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, "0"), + expectedWatchResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), "0"), + expectedWatchResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), "0"), + expectedWatchResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, "0"), + expectedWatchResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=true", + opts: listOptions(false, pointer.Bool(true), "0"), + expectedWatchResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), "0"), + expectedWatchResourceVersion: 0, + }, + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | 95 | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, "95"), + expectedWatchResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), "95"), + expectedWatchResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), "95"), + expectedWatchResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, "95"), + expectedWatchResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=true", + opts: listOptions(false, pointer.Bool(true), "95"), + expectedWatchResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), "95"), + expectedWatchResourceVersion: 95, + }, + } + + for _, scenario := range scenarios { + t.Run(scenario.name, func(t *testing.T) { + backingStorage := &dummyStorage{} + cacher, _, err := newTestCacher(backingStorage) + require.NoError(t, err, "couldn't create cacher") + defer cacher.Stop() + + parsedResourceVersion := 0 + if len(scenario.opts.ResourceVersion) > 0 { + parsedResourceVersion, err = strconv.Atoi(scenario.opts.ResourceVersion) + require.NoError(t, err) + } + + actualResourceVersion, err := cacher.getWatchCacheResourceVersion(context.TODO(), uint64(parsedResourceVersion), scenario.opts) + require.NoError(t, err) + require.Equal(t, uint64(scenario.expectedWatchResourceVersion), actualResourceVersion, "received unexpected ResourceVersion") + }) + } +} + +// TestGetBookmarkAfterResourceVersionLockedFunc test the following cases: +// +// +-----------------+---------------------+-----------------------+ +// | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | +// +=================+=====================+=======================+ +// | Unset | true/false | nil/true/false | +// | 0 | true/false | nil/true/false | +// | 95 | true/false | nil/true/false | +// +-----------------+---------------------+-----------------------+ +// where: +// - false indicates the value of the param was set to "false" by a test case +// - true indicates the value of the param was set to "true" by a test case +func TestGetBookmarkAfterResourceVersionLockedFunc(t *testing.T) { + listOptions := func(allowBookmarks bool, sendInitialEvents *bool, rv string) storage.ListOptions { + p := storage.Everything + p.AllowWatchBookmarks = allowBookmarks + + opts := storage.ListOptions{} + opts.Predicate = p + opts.SendInitialEvents = sendInitialEvents + opts.ResourceVersion = rv + return opts + } + + scenarios := []struct { + name string + opts storage.ListOptions + requiredResourceVersion int + watchCacheResourceVersion int + + expectedBookmarkResourceVersion int + }{ + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | Unset | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 100, + }, + { + name: "RV=unset, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=true", + opts: listOptions(false, pointer.Bool(true), ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=unset, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), ""), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | 0 | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 99, + }, + { + name: "RV=0, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=true", + opts: listOptions(false, pointer.Bool(true), "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=0, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), "0"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + // +-----------------+---------------------+-----------------------+ + // | ResourceVersion | AllowWatchBookmarks | SendInitialEvents | + // +=================+=====================+=======================+ + // | 95 | true/false | nil/true/false | + // +-----------------+---------------------+-----------------------+ + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=nil", + opts: listOptions(true, nil, "95"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=true", + opts: listOptions(true, pointer.Bool(true), "95"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 95, + }, + { + name: "RV=95, allowWatchBookmarks=true, sendInitialEvents=false", + opts: listOptions(true, pointer.Bool(false), "95"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=nil", + opts: listOptions(false, nil, "95"), + requiredResourceVersion: 100, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=true", + opts: listOptions(false, pointer.Bool(true), "95"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + { + name: "RV=95, allowWatchBookmarks=false, sendInitialEvents=false", + opts: listOptions(false, pointer.Bool(false), "95"), + requiredResourceVersion: 0, + watchCacheResourceVersion: 99, + expectedBookmarkResourceVersion: 0, + }, + } + for _, scenario := range scenarios { + t.Run(scenario.name, func(t *testing.T) { + backingStorage := &dummyStorage{} + cacher, _, err := newTestCacher(backingStorage) + require.NoError(t, err, "couldn't create cacher") + + defer cacher.Stop() + if err := cacher.ready.wait(context.Background()); err != nil { + t.Fatalf("unexpected error waiting for the cache to be ready") + } + + cacher.watchCache.UpdateResourceVersion(fmt.Sprintf("%d", scenario.watchCacheResourceVersion)) + parsedResourceVersion := 0 + if len(scenario.opts.ResourceVersion) > 0 { + parsedResourceVersion, err = strconv.Atoi(scenario.opts.ResourceVersion) + require.NoError(t, err) + } + + getBookMarkFn, err := cacher.getBookmarkAfterResourceVersionLockedFunc(uint64(parsedResourceVersion), uint64(scenario.requiredResourceVersion), scenario.opts) + require.NoError(t, err) + cacher.watchCache.RLock() + defer cacher.watchCache.RUnlock() + getBookMarkResourceVersion := getBookMarkFn() + require.Equal(t, uint64(scenario.expectedBookmarkResourceVersion), getBookMarkResourceVersion, "received unexpected ResourceVersion") + }) + } +}