Test recursive in TestGetListCacheBypass and separate overrides

Kubernetes-commit: 6d3bff83213b35797b23e89c90bfe939dd30c2cd
This commit is contained in:
Marek Siarkowicz 2025-03-04 20:07:41 +01:00 committed by Kubernetes Publisher
parent 84cc815637
commit f76f81aa6f
1 changed files with 84 additions and 60 deletions

View File

@ -218,53 +218,87 @@ func (d *dummyCacher) Ready() bool {
func TestGetListCacheBypass(t *testing.T) {
type opts struct {
Recursive bool
ResourceVersion string
ResourceVersionMatch metav1.ResourceVersionMatch
Limit int64
Continue string
}
toInternalOpts := func(opt opts) *internalversion.ListOptions {
return &internalversion.ListOptions{
ResourceVersion: opt.ResourceVersion,
ResourceVersionMatch: opt.ResourceVersionMatch,
Limit: opt.Limit,
Continue: opt.Continue,
}
}
toStorageOpts := func(opt opts) storage.ListOptions {
return storage.ListOptions{
Recursive: opt.Recursive,
ResourceVersion: opt.ResourceVersion,
ResourceVersionMatch: opt.ResourceVersionMatch,
Predicate: storage.SelectionPredicate{
Continue: opt.Continue,
Limit: opt.Limit,
},
}
}
keyPrefix := "/pods/"
continueOnRev1, err := storage.EncodeContinue(keyPrefix+"foo", keyPrefix, 1)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
testCases := map[opts]bool{}
testCases[opts{}] = false
testCases[opts{Limit: 100}] = false
testCases[opts{Continue: "continue"}] = true
testCases[opts{Limit: 100, Continue: "continue"}] = true
testCases[opts{}] = true
testCases[opts{Limit: 100}] = true
testCases[opts{Continue: continueOnRev1}] = true
testCases[opts{Limit: 100, Continue: continueOnRev1}] = true
testCases[opts{ResourceVersion: "0"}] = false
testCases[opts{ResourceVersion: "0", Limit: 100}] = false
testCases[opts{ResourceVersion: "0", Continue: "continue"}] = true
testCases[opts{ResourceVersion: "0", Limit: 100, Continue: "continue"}] = true
testCases[opts{ResourceVersion: "0", Continue: continueOnRev1}] = true
testCases[opts{ResourceVersion: "0", Limit: 100, Continue: continueOnRev1}] = true
testCases[opts{ResourceVersion: "0", ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan}] = false
testCases[opts{ResourceVersion: "0", ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan, Limit: 100}] = false
testCases[opts{ResourceVersion: "1"}] = false
testCases[opts{ResourceVersion: "1", Limit: 100}] = true
testCases[opts{ResourceVersion: "1", Continue: "continue"}] = true
testCases[opts{ResourceVersion: "1", Limit: 100, Continue: "continue"}] = true
testCases[opts{ResourceVersion: "1", ResourceVersionMatch: metav1.ResourceVersionMatchExact}] = true
testCases[opts{ResourceVersion: "1", ResourceVersionMatch: metav1.ResourceVersionMatchExact, Limit: 100}] = true
testCases[opts{ResourceVersion: "1", ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan}] = false
testCases[opts{ResourceVersion: "1", ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan, Limit: 100}] = false
// Bypass for most requests doesn't depend on Recursive
for opts, expectBypass := range testCases {
opts.Recursive = true
testCases[opts] = expectBypass
}
// Continue is ignored on non recursive LIST
testCases[opts{ResourceVersion: "1", Continue: continueOnRev1}] = true
testCases[opts{ResourceVersion: "1", Continue: continueOnRev1, Limit: 100}] = true
for _, rv := range []string{"", "0", "1"} {
for _, match := range []metav1.ResourceVersionMatch{"", metav1.ResourceVersionMatchExact, metav1.ResourceVersionMatchNotOlderThan} {
for _, c := range []string{"", "continue"} {
for _, continueKey := range []string{"", continueOnRev1} {
for _, limit := range []int64{0, 100} {
errs := validation.ValidateListOptions(&internalversion.ListOptions{
ResourceVersion: rv,
ResourceVersionMatch: match,
Limit: limit,
Continue: c,
}, false)
if len(errs) != 0 {
continue
}
opt := opts{
ResourceVersion: rv,
ResourceVersionMatch: match,
Limit: limit,
Continue: c,
}
_, found := testCases[opt]
if !found {
t.Errorf("Test case not covered, but passes validation: %+v", opt)
for _, recursive := range []bool{true, false} {
opt := opts{
Recursive: recursive,
ResourceVersion: rv,
ResourceVersionMatch: match,
Limit: limit,
Continue: continueKey,
}
if errs := validation.ValidateListOptions(toInternalOpts(opt), false); len(errs) != 0 {
continue
}
if _, _, err = storage.ValidateListOptions(keyPrefix, storage.APIObjectVersioner{}, toStorageOpts(opt)); err != nil {
continue
}
_, found := testCases[opt]
if !found {
t.Errorf("Test case not covered, but passes validation: %+v", opt)
}
}
}
@ -273,35 +307,37 @@ func TestGetListCacheBypass(t *testing.T) {
}
for opt := range testCases {
errs := validation.ValidateListOptions(&internalversion.ListOptions{
ResourceVersion: opt.ResourceVersion,
ResourceVersionMatch: opt.ResourceVersionMatch,
Limit: opt.Limit,
Continue: opt.Continue,
}, false)
if len(errs) != 0 {
if errs := validation.ValidateListOptions(toInternalOpts(opt), false); len(errs) != 0 {
t.Errorf("Invalid LIST request that should not be tested %+v", opt)
continue
}
if _, _, err = storage.ValidateListOptions(keyPrefix, storage.APIObjectVersioner{}, toStorageOpts(opt)); err != nil {
t.Errorf("Invalid LIST request that should not be tested %+v", opt)
continue
}
}
t.Run("ConsistentListFromStorage", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
testCases[opts{}] = true
testCases[opts{Limit: 100}] = true
runTestCases := func(t *testing.T, testcases map[opts]bool, overrides ...map[opts]bool) {
for opt, expectBypass := range testCases {
testGetListCacheBypass(t, storage.ListOptions{
ResourceVersion: opt.ResourceVersion,
ResourceVersionMatch: opt.ResourceVersionMatch,
Predicate: storage.SelectionPredicate{
Continue: opt.Continue,
Limit: opt.Limit,
},
}, expectBypass)
for _, override := range overrides {
if bypass, ok := override[opt]; ok {
expectBypass = bypass
}
}
testGetListCacheBypass(t, toStorageOpts(opt), expectBypass)
}
}
consistentListFromCacheOverrides := map[opts]bool{}
for _, recursive := range []bool{true, false} {
consistentListFromCacheOverrides[opts{Recursive: recursive}] = false
consistentListFromCacheOverrides[opts{Limit: 100, Recursive: recursive}] = false
}
t.Run("ConsistentListFromCache=false", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
runTestCases(t, testCases)
})
t.Run("ConsistentListFromCache", func(t *testing.T) {
t.Run("ConsistentListFromCache=true", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, true)
// TODO(p0lyn0mial): the following tests assume that etcdfeature.DefaultFeatureSupportChecker.Supports(storage.RequestWatchProgress)
@ -311,19 +347,7 @@ func TestGetListCacheBypass(t *testing.T) {
// However in CI all test are run and there must be a test(s) that properly
// initialize the storage layer so that the mentioned method evaluates to true
forceRequestWatchProgressSupport(t)
testCases[opts{}] = false
testCases[opts{Limit: 100}] = false
for opt, expectBypass := range testCases {
testGetListCacheBypass(t, storage.ListOptions{
ResourceVersion: opt.ResourceVersion,
ResourceVersionMatch: opt.ResourceVersionMatch,
Predicate: storage.SelectionPredicate{
Continue: opt.Continue,
Limit: opt.Limit,
},
}, expectBypass)
}
runTestCases(t, testCases, consistentListFromCacheOverrides)
})
}