Skip to content

Commit abf0c07

Browse files
authored
Merge pull request kubernetes-sigs#311 from sebgl/fake-client-list-options
🐛 fix labels list option in fake client
2 parents 2027a41 + e9c5505 commit abf0c07

File tree

4 files changed

+98
-27
lines changed

4 files changed

+98
-27
lines changed

pkg/cache/internal/cache_reader.go

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"k8s.io/apimachinery/pkg/selection"
3131
"k8s.io/client-go/tools/cache"
3232
"sigs.k8s.io/controller-runtime/pkg/client"
33+
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
3334
)
3435

3536
// CacheReader is a CacheReader
@@ -118,33 +119,19 @@ func (c *CacheReader) List(_ context.Context, out runtime.Object, opts ...client
118119
labelSel = listOpts.LabelSelector
119120
}
120121

121-
outItems, err := c.getListItems(objs, labelSel)
122-
if err != nil {
123-
return err
124-
}
125-
return apimeta.SetList(out, outItems)
126-
}
127-
128-
func (c *CacheReader) getListItems(objs []interface{}, labelSel labels.Selector) ([]runtime.Object, error) {
129-
outItems := make([]runtime.Object, 0, len(objs))
122+
runtimeObjs := make([]runtime.Object, 0, len(objs))
130123
for _, item := range objs {
131124
obj, isObj := item.(runtime.Object)
132125
if !isObj {
133-
return nil, fmt.Errorf("cache contained %T, which is not an Object", obj)
126+
return fmt.Errorf("cache contained %T, which is not an Object", obj)
134127
}
135-
meta, err := apimeta.Accessor(obj)
136-
if err != nil {
137-
return nil, err
138-
}
139-
if labelSel != nil {
140-
lbls := labels.Set(meta.GetLabels())
141-
if !labelSel.Matches(lbls) {
142-
continue
143-
}
144-
}
145-
outItems = append(outItems, obj.DeepCopyObject())
128+
runtimeObjs = append(runtimeObjs, obj)
129+
}
130+
filteredItems, err := objectutil.FilterWithLabels(runtimeObjs, labelSel)
131+
if err != nil {
132+
return err
146133
}
147-
return outItems, nil
134+
return apimeta.SetList(out, filteredItems)
148135
}
149136

150137
// objectKeyToStorageKey converts an object key to store key.

pkg/client/fake/client.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"sigs.k8s.io/controller-runtime/pkg/client"
3333
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3434
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
35+
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
3536
)
3637

3738
var (
@@ -114,7 +115,25 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
114115
}
115116
decoder := scheme.Codecs.UniversalDecoder()
116117
_, _, err = decoder.Decode(j, nil, obj)
117-
return err
118+
if err != nil {
119+
return err
120+
}
121+
122+
if listOpts.LabelSelector != nil {
123+
objs, err := meta.ExtractList(obj)
124+
if err != nil {
125+
return err
126+
}
127+
filteredObjs, err := objectutil.FilterWithLabels(objs, listOpts.LabelSelector)
128+
if err != nil {
129+
return err
130+
}
131+
err = meta.SetList(obj, filteredObjs)
132+
if err != nil {
133+
return err
134+
}
135+
}
136+
return nil
118137
}
119138

120139
func (c *fakeClient) Create(ctx context.Context, obj runtime.Object) error {

pkg/client/fake/client_test.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
var _ = Describe("Fake client", func() {
3232
var dep *appsv1.Deployment
33+
var dep2 *appsv1.Deployment
3334
var cm *corev1.ConfigMap
3435
var cl client.Client
3536

@@ -40,6 +41,15 @@ var _ = Describe("Fake client", func() {
4041
Namespace: "ns1",
4142
},
4243
}
44+
dep2 = &appsv1.Deployment{
45+
ObjectMeta: metav1.ObjectMeta{
46+
Name: "test-deployment-2",
47+
Namespace: "ns1",
48+
Labels: map[string]string{
49+
"test-label": "label-value",
50+
},
51+
},
52+
}
4353
cm = &corev1.ConfigMap{
4454
ObjectMeta: metav1.ObjectMeta{
4555
Name: "test-cm",
@@ -69,8 +79,20 @@ var _ = Describe("Fake client", func() {
6979
list := &appsv1.DeploymentList{}
7080
err := cl.List(nil, list, client.InNamespace("ns1"))
7181
Expect(err).To(BeNil())
82+
Expect(list.Items).To(HaveLen(2))
83+
Expect(list.Items).To(ConsistOf(*dep, *dep2))
84+
})
85+
86+
It("should support filtering by labels", func() {
87+
By("Listing deployments with a particular label")
88+
list := &appsv1.DeploymentList{}
89+
err := cl.List(nil, list, client.InNamespace("ns1"),
90+
client.MatchingLabels(map[string]string{
91+
"test-label": "label-value",
92+
}))
93+
Expect(err).To(BeNil())
7294
Expect(list.Items).To(HaveLen(1))
73-
Expect(list.Items).To(ConsistOf(*dep))
95+
Expect(list.Items).To(ConsistOf(*dep2))
7496
})
7597

7698
It("should be able to Create", func() {
@@ -129,13 +151,14 @@ var _ = Describe("Fake client", func() {
129151
list := &appsv1.DeploymentList{}
130152
err = cl.List(nil, list, client.InNamespace("ns1"))
131153
Expect(err).To(BeNil())
132-
Expect(list.Items).To(HaveLen(0))
154+
Expect(list.Items).To(HaveLen(1))
155+
Expect(list.Items).To(ConsistOf(*dep2))
133156
})
134157
}
135158

136159
Context("with default scheme.Scheme", func() {
137160
BeforeEach(func(done Done) {
138-
cl = NewFakeClient(dep, cm)
161+
cl = NewFakeClient(dep, dep2, cm)
139162
close(done)
140163
})
141164
AssertClientBehavior()
@@ -146,7 +169,7 @@ var _ = Describe("Fake client", func() {
146169
scheme := runtime.NewScheme()
147170
corev1.AddToScheme(scheme)
148171
appsv1.AddToScheme(scheme)
149-
cl = NewFakeClientWithScheme(scheme, dep, cm)
172+
cl = NewFakeClientWithScheme(scheme, dep, dep2, cm)
150173
close(done)
151174
})
152175
AssertClientBehavior()

pkg/internal/objectutil/filter.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2018 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 objectutil
18+
19+
import (
20+
apimeta "k8s.io/apimachinery/pkg/api/meta"
21+
"k8s.io/apimachinery/pkg/labels"
22+
"k8s.io/apimachinery/pkg/runtime"
23+
)
24+
25+
// FilterWithLabels returns a copy of the items in objs matching labelSel
26+
func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) {
27+
outItems := make([]runtime.Object, 0, len(objs))
28+
for _, obj := range objs {
29+
meta, err := apimeta.Accessor(obj)
30+
if err != nil {
31+
return nil, err
32+
}
33+
if labelSel != nil {
34+
lbls := labels.Set(meta.GetLabels())
35+
if !labelSel.Matches(lbls) {
36+
continue
37+
}
38+
}
39+
outItems = append(outItems, obj.DeepCopyObject())
40+
}
41+
return outItems, nil
42+
}

0 commit comments

Comments
 (0)