From 711772a1e15288d813a830780317a134df9acb5c Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Thu, 22 Aug 2024 20:04:37 +0200 Subject: [PATCH] Adding tests for using indexers in tests --- .../pkg/storage/cacher/cacher_test.go | 6 + .../storage/cacher/cacher_whitebox_test.go | 147 +++++++ .../apiserver/pkg/storage/etcd3/store_test.go | 5 + .../pkg/storage/testing/store_tests.go | 400 ++++++++++++++++++ .../apiserver/pkg/storage/testing/utils.go | 41 ++ .../pkg/storage/testing/watcher_tests.go | 43 +- 6 files changed, 601 insertions(+), 41 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_test.go b/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_test.go index 013fcf81e3b..e53fbec477a 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher_test.go @@ -256,6 +256,12 @@ func TestListResourceVersionMatch(t *testing.T) { // TODO(#109831): Enable use of this test and run it. } +func TestNamespaceScopedList(t *testing.T) { + ctx, cacher, terminate := testSetup(t, withSpecNodeNameIndexerFuncs) + t.Cleanup(terminate) + storagetesting.RunTestNamespaceScopedList(ctx, t, cacher) +} + func TestGuaranteedUpdate(t *testing.T) { // TODO(#109831): Enable use of this test and run it. } 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 fa7257f216d..460dd0c090b 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 @@ -49,6 +49,7 @@ import ( "k8s.io/apiserver/pkg/storage/cacher/metrics" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" etcdfeature "k8s.io/apiserver/pkg/storage/feature" + storagetesting "k8s.io/apiserver/pkg/storage/testing" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" k8smetrics "k8s.io/component-base/metrics" @@ -2837,3 +2838,149 @@ func forceRequestWatchProgressSupport(t *testing.T) { t.Fatalf("failed to wait for required %v storage feature to initialize", storage.RequestWatchProgress) } } + +func TestListIndexer(t *testing.T) { + ctx, cacher, terminate := testSetup(t, withSpecNodeNameIndexerFuncs) + t.Cleanup(terminate) + tests := []struct { + name string + requestedNamespace string + recursive bool + fieldSelector fields.Selector + indexFields []string + expectIndex string + }{ + { + name: "request without namespace, without field selector", + recursive: true, + fieldSelector: fields.Everything(), + }, + { + name: "request without namespace, field selector with metadata.namespace", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("metadata.namespace=namespace"), + }, + { + name: "request without namespace, field selector with spec.nodename", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=node"), + indexFields: []string{"spec.nodeName"}, + expectIndex: "f:spec.nodeName", + }, + { + name: "request without namespace, field selector with spec.nodename to filter out", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("spec.nodeName!=node"), + indexFields: []string{"spec.nodeName"}, + }, + { + name: "request with namespace, without field selector", + requestedNamespace: "namespace", + recursive: true, + fieldSelector: fields.Everything(), + }, + { + name: "request with namespace, field selector with matched metadata.namespace", + requestedNamespace: "namespace", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("metadata.namespace=namespace"), + }, + { + name: "request with namespace, field selector with non-matched metadata.namespace", + requestedNamespace: "namespace", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("metadata.namespace=namespace"), + }, + { + name: "request with namespace, field selector with spec.nodename", + requestedNamespace: "namespace", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=node"), + indexFields: []string{"spec.nodeName"}, + expectIndex: "f:spec.nodeName", + }, + { + name: "request with namespace, field selector with spec.nodename to filter out", + requestedNamespace: "namespace", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("spec.nodeName!=node"), + indexFields: []string{"spec.nodeName"}, + }, + { + name: "request without namespace, field selector with metadata.name", + recursive: true, + fieldSelector: fields.ParseSelectorOrDie("metadata.name=name"), + }, + { + name: "request without namespace, field selector with metadata.name and metadata.namespace", + recursive: true, + fieldSelector: fields.SelectorFromSet(fields.Set{ + "metadata.name": "name", + "metadata.namespace": "namespace", + }), + }, + { + name: "request without namespace, field selector with metadata.name and spec.nodeName", + recursive: true, + fieldSelector: fields.SelectorFromSet(fields.Set{ + "metadata.name": "name", + "spec.nodeName": "node", + }), + indexFields: []string{"spec.nodeName"}, + expectIndex: "f:spec.nodeName", + }, + { + name: "request without namespace, field selector with metadata.name, and with spec.nodeName to filter out watch", + recursive: true, + fieldSelector: fields.AndSelectors( + fields.ParseSelectorOrDie("spec.nodeName!=node"), + fields.SelectorFromSet(fields.Set{"metadata.name": "name"}), + ), + indexFields: []string{"spec.nodeName"}, + }, + { + name: "request with namespace, with field selector metadata.name", + requestedNamespace: "namespace", + fieldSelector: fields.ParseSelectorOrDie("metadata.name=name"), + }, + { + name: "request with namespace, with field selector metadata.name and metadata.namespace", + requestedNamespace: "namespace", + fieldSelector: fields.SelectorFromSet(fields.Set{ + "metadata.name": "name", + "metadata.namespace": "namespace", + }), + }, + { + name: "request with namespace, with field selector metadata.name, metadata.namespace and spec.nodename", + requestedNamespace: "namespace", + fieldSelector: fields.SelectorFromSet(fields.Set{ + "metadata.name": "name", + "metadata.namespace": "namespace", + "spec.nodeName": "node", + }), + indexFields: []string{"spec.nodeName"}, + }, + { + name: "request with namespace, with field selector metadata.name, metadata.namespace, and with spec.nodename to filter out", + requestedNamespace: "namespace", + fieldSelector: fields.AndSelectors( + fields.ParseSelectorOrDie("spec.nodeName!=node"), + fields.SelectorFromSet(fields.Set{"metadata.name": "name", "metadata.namespace": "namespace"}), + ), + indexFields: []string{"spec.nodeName"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pred := storagetesting.CreatePodPredicate(tt.fieldSelector, true, tt.indexFields) + _, _, usedIndex, err := cacher.listItems(ctx, 0, "/pods/"+tt.requestedNamespace, pred, tt.recursive) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if usedIndex != tt.expectIndex { + t.Errorf("Index doesn't match, expected: %q, got: %q", tt.expectIndex, usedIndex) + } + }) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go b/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go index af5b52c2ea6..d8dce71b791 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go @@ -284,6 +284,11 @@ func TestListContinuationWithFilter(t *testing.T) { storagetesting.RunTestListContinuationWithFilter(ctx, t, store, validation) } +func TestNamespaceScopedList(t *testing.T) { + ctx, store, _ := testSetup(t) + storagetesting.RunTestNamespaceScopedList(ctx, t, store) +} + func compactStorage(etcdClient *clientv3.Client) storagetesting.Compaction { return func(ctx context.Context, t *testing.T, resourceVersion string) { versioner := storage.APIObjectVersioner{} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/testing/store_tests.go b/staging/src/k8s.io/apiserver/pkg/storage/testing/store_tests.go index 0c17de99b76..765cfc04834 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/testing/store_tests.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/testing/store_tests.go @@ -2759,3 +2759,403 @@ func RunTestListPaging(ctx context.Context, t *testing.T, store storage.Interfac t.Errorf("unexpected items: %#v", names) } } + +func RunTestNamespaceScopedList(ctx context.Context, t *testing.T, store storage.Interface) { + tests := []struct { + name string + requestedNamespace string + recursive bool + indexFields []string + fieldSelector func(namespace string) fields.Selector + inputPods func(namespace string) []example.Pod + expectPods func(namespace string) []example.Pod + }{ + { + name: "request without namespace, without field selector", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.Everything() }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", "ns1"), + *baseNamespacedPod("foo2", "ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", "ns1"), + *baseNamespacedPod("foo2", "ns2"), + } + }, + }, + { + name: "request without namespace, field selector with metadata.namespace", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{"metadata.namespace": namespace + "ns1"}) + }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + } + }, + }, + { + name: "request without namespace, field selector with spec.nodename", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.ParseSelectorOrDie("spec.nodeName=bar1") + }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + } + }, + }, + { + name: "request without namespace, field selector with spec.nodename to filter out", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.ParseSelectorOrDie("spec.nodeName!=bar1") }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + } + }, + }, + { + name: "request with namespace, without field selector", + requestedNamespace: "ns1", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.Everything() }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPod("foo2", namespace+"ns1"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + } + }, + }, + { + name: "request with namespace, field selector with matched metadata.namespace", + requestedNamespace: "ns1", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{"metadata.namespace": namespace + "ns1"}) + }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + } + }, + }, + { + name: "request with namespace, field selector with non-matched metadata.namespace", + requestedNamespace: "ns1", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{"metadata.namespace": namespace + "ns2"}) + }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPodUpdated("foo2", namespace+"ns1"), + *baseNamespacedPodUpdated("foo2", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { return []example.Pod{} }, + }, + { + name: "request with namespace, field selector with spec.nodename", + requestedNamespace: "ns1", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.ParseSelectorOrDie("spec.nodeName=bar2") }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns2", "bar2"), + *baseNamespacedPodAssigned("foo2", namespace+"ns1", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo2", namespace+"ns1", "bar2"), + } + }, + }, + { + name: "request with namespace, field selector with spec.nodename to filter out", + requestedNamespace: "ns2", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.ParseSelectorOrDie("spec.nodeName!=bar1") }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPodAssigned("foo3", namespace+"ns2", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + } + }, + }, + { + name: "request without namespace, field selector with metadata.name", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { return fields.ParseSelectorOrDie("metadata.name=foo1") }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPod("foo2", namespace+"ns1"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + } + }, + }, + { + name: "request without namespace, field selector with metadata.name and metadata.namespace", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{ + "metadata.name": "foo1", + "metadata.namespace": namespace + "ns1", + }) + }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + } + }, + }, + { + name: "request without namespace, field selector with metadata.name and spec.nodeName", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{ + "metadata.name": "foo1", + "spec.nodeName": "bar1", + }) + }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns1", "bar1"), + } + }, + }, + { + name: "request without namespace, field selector with metadata.name, and with spec.nodeName to filter out watch", + recursive: true, + fieldSelector: func(namespace string) fields.Selector { + return fields.AndSelectors( + fields.ParseSelectorOrDie("spec.nodeName!=bar1"), + fields.SelectorFromSet(fields.Set{"metadata.name": "foo1"}), + ) + }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns2", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns3", "bar2"), + *baseNamespacedPodAssigned("foo2", namespace+"ns3", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns3", "bar2"), + } + }, + }, + { + name: "request with namespace, with field selector metadata.name", + requestedNamespace: "ns1", + fieldSelector: func(namespace string) fields.Selector { return fields.ParseSelectorOrDie("metadata.name=foo1") }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPod("foo2", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + } + }, + }, + { + name: "request with namespace, with field selector metadata.name and metadata.namespace", + requestedNamespace: "ns1", + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{ + "metadata.name": "foo1", + "metadata.namespace": namespace + "ns1", + }) + }, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPod("foo2", namespace+"ns2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + } + }, + }, + { + name: "request with namespace, with field selector metadata.name, metadata.namespace and spec.nodename", + requestedNamespace: "ns2", + fieldSelector: func(namespace string) fields.Selector { + return fields.SelectorFromSet(fields.Set{ + "metadata.name": "foo2", + "metadata.namespace": namespace + "ns2", + "spec.nodeName": "bar1", + }) + }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPod("foo1", namespace+"ns2"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns3", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns3", "bar1"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar1"), + } + }, + }, + { + name: "request with namespace, with field selector metadata.name, metadata.namespace, and with spec.nodename to filter out", + requestedNamespace: "ns2", + fieldSelector: func(namespace string) fields.Selector { + return fields.AndSelectors( + fields.ParseSelectorOrDie("spec.nodeName!=bar2"), + fields.SelectorFromSet(fields.Set{"metadata.name": "foo1", "metadata.namespace": namespace + "ns2"}), + ) + }, + indexFields: []string{"spec.nodeName"}, + inputPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPod("foo1", namespace+"ns1"), + *baseNamespacedPod("foo2", namespace+"ns1"), + *baseNamespacedPodAssigned("foo1", namespace+"ns2", "bar1"), + *baseNamespacedPodAssigned("foo2", namespace+"ns2", "bar2"), + *baseNamespacedPodAssigned("foo1", namespace+"ns3", "bar2"), + } + }, + expectPods: func(namespace string) []example.Pod { + return []example.Pod{ + *baseNamespacedPodAssigned("foo1", namespace+"ns2", "bar1"), + } + }, + }, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + podNames := map[string]struct{}{} + namespace := fmt.Sprintf("t%d-", i) + for _, pod := range tt.inputPods(namespace) { + out := &example.Pod{} + key := computePodKey(&pod) + podNames[key] = struct{}{} + err := store.Create(ctx, key, &pod, out, 0) + if err != nil { + t.Fatalf("GuaranteedUpdate failed: %v", err) + } + } + opts := storage.ListOptions{ + ResourceVersion: "", + Predicate: CreatePodPredicate(tt.fieldSelector(namespace), true, tt.indexFields), + Recursive: true, + } + listOut := &example.PodList{} + path := "/pods/" + if tt.requestedNamespace != "" { + path += namespace + tt.requestedNamespace + } + if err := store.GetList(ctx, path, opts, listOut); err != nil { + t.Errorf("Unexpected error: %v", err) + } + i := 0 + for _, pod := range listOut.Items { + if _, found := podNames[computePodKey(&pod)]; !found { + continue + } + pod.ResourceVersion = "" + listOut.Items[i] = pod + i++ + } + listOut.Items = listOut.Items[:i] + + expectNoDiff(t, "incorrect list pods", tt.expectPods(namespace), listOut.Items) + }) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/testing/utils.go b/staging/src/k8s.io/apiserver/pkg/storage/testing/utils.go index e30f086184a..ad3bd4b4312 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/testing/utils.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/testing/utils.go @@ -30,6 +30,8 @@ import ( "github.com/google/go-cmp/cmp" "k8s.io/apimachinery/pkg/api/meta" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" @@ -357,3 +359,42 @@ func (s sortablePodList) Less(i, j int) bool { func (s sortablePodList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func CreatePodPredicate(field fields.Selector, namespaceScoped bool, indexField []string) storage.SelectionPredicate { + return storage.SelectionPredicate{ + Label: labels.Everything(), + Field: field, + GetAttrs: determinePodGetAttrFunc(namespaceScoped, indexField), + IndexFields: indexField, + } +} + +func determinePodGetAttrFunc(namespaceScoped bool, indexField []string) storage.AttrFunc { + if indexField != nil { + if namespaceScoped { + return namespacedScopedNodeNameAttrFunc + } + return clusterScopedNodeNameAttrFunc + } + if namespaceScoped { + return storage.DefaultNamespaceScopedAttr + } + return storage.DefaultClusterScopedAttr +} + +func namespacedScopedNodeNameAttrFunc(obj runtime.Object) (labels.Set, fields.Set, error) { + pod := obj.(*example.Pod) + return nil, fields.Set{ + "spec.nodeName": pod.Spec.NodeName, + "metadata.name": pod.ObjectMeta.Name, + "metadata.namespace": pod.ObjectMeta.Namespace, + }, nil +} + +func clusterScopedNodeNameAttrFunc(obj runtime.Object) (labels.Set, fields.Set, error) { + pod := obj.(*example.Pod) + return nil, fields.Set{ + "spec.nodeName": pod.Spec.NodeName, + "metadata.name": pod.ObjectMeta.Name, + }, nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/testing/watcher_tests.go b/staging/src/k8s.io/apiserver/pkg/storage/testing/watcher_tests.go index dee88a0e61d..47ec58d6a27 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/testing/watcher_tests.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/testing/watcher_tests.go @@ -674,7 +674,7 @@ func RunTestClusterScopedWatch(ctx context.Context, t *testing.T, store storage. watchKey += "/" + tt.requestedName } - predicate := createPodPredicate(tt.fieldSelector, false, tt.indexFields) + predicate := CreatePodPredicate(tt.fieldSelector, false, tt.indexFields) list := &example.PodList{} opts := storage.ListOptions{ @@ -988,7 +988,7 @@ func RunTestNamespaceScopedWatch(ctx context.Context, t *testing.T, store storag } } - predicate := createPodPredicate(tt.fieldSelector, true, tt.indexFields) + predicate := CreatePodPredicate(tt.fieldSelector, true, tt.indexFields) list := &example.PodList{} opts := storage.ListOptions{ @@ -1585,45 +1585,6 @@ type testWatchStruct struct { watchType watch.EventType } -func createPodPredicate(field fields.Selector, namespaceScoped bool, indexField []string) storage.SelectionPredicate { - return storage.SelectionPredicate{ - Label: labels.Everything(), - Field: field, - GetAttrs: determinePodGetAttrFunc(namespaceScoped, indexField), - IndexFields: indexField, - } -} - -func determinePodGetAttrFunc(namespaceScoped bool, indexField []string) storage.AttrFunc { - if indexField != nil { - if namespaceScoped { - return namespacedScopedNodeNameAttrFunc - } - return clusterScopedNodeNameAttrFunc - } - if namespaceScoped { - return storage.DefaultNamespaceScopedAttr - } - return storage.DefaultClusterScopedAttr -} - -func namespacedScopedNodeNameAttrFunc(obj runtime.Object) (labels.Set, fields.Set, error) { - pod := obj.(*example.Pod) - return nil, fields.Set{ - "spec.nodeName": pod.Spec.NodeName, - "metadata.name": pod.ObjectMeta.Name, - "metadata.namespace": pod.ObjectMeta.Namespace, - }, nil -} - -func clusterScopedNodeNameAttrFunc(obj runtime.Object) (labels.Set, fields.Set, error) { - pod := obj.(*example.Pod) - return nil, fields.Set{ - "spec.nodeName": pod.Spec.NodeName, - "metadata.name": pod.ObjectMeta.Name, - }, nil -} - func basePod(podName string) *example.Pod { return baseNamespacedPod(podName, "") }