diff --git a/pkg/storage/memorystorage/watchcache/watch_cache.go b/pkg/storage/memorystorage/watchcache/watch_cache.go index 639452dab..6a4e8426c 100644 --- a/pkg/storage/memorystorage/watchcache/watch_cache.go +++ b/pkg/storage/memorystorage/watchcache/watch_cache.go @@ -112,6 +112,19 @@ func GetKeyFunc(gvr schema.GroupVersionResource, isNamespaced bool) keyFunc { return kc } +func GetAttrsFunc(obj runtime.Object) (labels.Set, fields.Set, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, nil, err + } + objLabels := accessor.GetLabels() + if objLabels == nil { + objLabels = make(map[string]string) + } + labelSet := labels.Set(objLabels) + return labelSet, nil, nil +} + func storeElementKey(obj interface{}) (string, error) { elem, ok := obj.(*StoreElement) if !ok { @@ -153,7 +166,7 @@ func NewWatchCache(capacity int, gvr schema.GroupVersionResource, isNamespaced b wc := &WatchCache{ capacity: capacity, KeyFunc: GetKeyFunc(gvr, isNamespaced), - getAttrsFunc: nil, + getAttrsFunc: GetAttrsFunc, cache: make([]*watch.Event, capacity), startIndex: 0, endIndex: 0, @@ -305,12 +318,26 @@ func (w *WatchCache) WaitUntilFreshAndList(opts *internal.ListOptions) ([]*Store continue } } + if filterLabelSelector(opts.LabelSelector, se.Labels) { + continue + } result = append(result, se) } } return result, w.resourceVersion, nil } +// filterLabelSelector returns true if the given label selector matches the given label set. else false. +func filterLabelSelector(labelSelector labels.Selector, label labels.Set) bool { + if labelSelector != nil && label == nil { + return true + } + if labelSelector != nil && label != nil && !labelSelector.Matches(label) { + return true + } + return false +} + // WaitUntilFreshAndGet returns list of pointers to objects. func (w *WatchCache) WaitUntilFreshAndGet(cluster, namespace, name string) (*StoreElement, error) { w.RLock() diff --git a/pkg/storage/memorystorage/watchcache/watch_cache_test.go b/pkg/storage/memorystorage/watchcache/watch_cache_test.go new file mode 100644 index 000000000..dea2f7c61 --- /dev/null +++ b/pkg/storage/memorystorage/watchcache/watch_cache_test.go @@ -0,0 +1,304 @@ +package watchcache + +import ( + "testing" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" +) + +func Test_filterLabelSelector(t *testing.T) { + type request struct { + labelSelector labels.Selector + label labels.Set + } + var tests = []struct { + name string + req request + before func(req *request) + want bool + }{ + { + name: "empty label selector", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + labelSelector: nil, + label: labels.Set{}, + }, + want: false, + }, + { + name: "empty label", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + labelSelector: labels.Everything(), + label: nil, + }, + want: true, + }, + { + name: "lable exist operator,but exist", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.Exists, nil) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + { + name: "lable exist operator,but not exist", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("app", selection.Exists, nil) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable not exist operator,but exist", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.DoesNotExist, nil) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable not exist operator,but not exist", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("app", selection.DoesNotExist, nil) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + { + name: "lable Equals operator,but not equals", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.Equals, []string{"prod"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable Equals operator,but equals", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.Equals, []string{"dev"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + { + name: "lable NotEquals operator,but equals", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.NotEquals, []string{"dev"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable NotEquals operator,but not equals", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.NotEquals, []string{"prod"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + { + name: "lable IN operator,but not in", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.In, []string{"prod", "test"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable IN operator,but in", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.In, []string{"prod", "test", "dev"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + { + name: "lable NotIn operator,but in", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.NotIn, []string{"prod", "test", "dev"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: true, + }, + { + name: "lable NotIn operator,but not in", + req: struct { + labelSelector labels.Selector + label labels.Set + }{ + labelSelector: labels.NewSelector(), + label: labels.Set{ + "env": "dev", + }, + }, + before: func(req *request) { + requirement, err := labels.NewRequirement("env", selection.NotIn, []string{"prod", "test"}) + if err != nil { + t.Fatal(err) + } + req.labelSelector = req.labelSelector.Add(labels.Requirements{*requirement}...) + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.before != nil { + tt.before(&tt.req) + } + if got := filterLabelSelector(tt.req.labelSelector, tt.req.label); got != tt.want { + t.Errorf("filterLabelSelector() = %v, want %v", got, tt.want) + } + }) + } +}