Skip to content

Commit 561de08

Browse files
committed
add test
Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
1 parent 1a8bba6 commit 561de08

File tree

3 files changed

+196
-12
lines changed

3 files changed

+196
-12
lines changed
Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package internal
17+
package cache
1818

1919
import (
2020
"context"
@@ -85,13 +85,23 @@ func (b *multiScopedCache) GetInformer(ctx context.Context, obj client.Object) (
8585
if err := setGroupVersionKind(b.scheme, obj); err != nil {
8686
return nil, err
8787
}
88-
return b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind()).GetInformer(ctx, obj)
88+
89+
cache, err := b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind())
90+
if err != nil {
91+
return nil, err
92+
}
93+
return cache.GetInformer(ctx, obj)
8994
}
9095

9196
// GetInformerForKind returns the underlying cache's GetInformerForKind based
9297
// on resource type.
9398
func (b *multiScopedCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (cache.Informer, error) {
94-
return b.cacheFromGVK(gvk).GetInformerForKind(ctx, gvk)
99+
100+
cache, err := b.cacheFromGVK(gvk)
101+
if err != nil {
102+
return nil, err
103+
}
104+
return cache.GetInformerForKind(ctx, gvk)
95105
}
96106

97107
// Start starts both the cluster and namespaced caches. Returned is an
@@ -137,38 +147,53 @@ func (b *multiScopedCache) IndexField(ctx context.Context, obj client.Object, fi
137147
if err := setGroupVersionKind(b.scheme, obj); err != nil {
138148
return err
139149
}
140-
return b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind()).IndexField(ctx, obj, field, extractValue)
150+
151+
cache, err := b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind())
152+
if err != nil {
153+
return err
154+
}
155+
return cache.IndexField(ctx, obj, field, extractValue)
141156
}
142157

143158
// Get returns the underlying cache's Get based on resource type.
144159
func (b *multiScopedCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
145160
if err := setGroupVersionKind(b.scheme, obj); err != nil {
146161
return err
147162
}
148-
return b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind()).Get(ctx, key, obj)
163+
164+
cache, err := b.cacheFromGVK(obj.GetObjectKind().GroupVersionKind())
165+
if err != nil {
166+
return err
167+
}
168+
return cache.Get(ctx, key, obj)
149169
}
150170

151171
// List returns the underlying cache's List based on resource type.
152172
func (b *multiScopedCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
153173
if err := setGroupVersionKind(b.scheme, list); err != nil {
154174
return err
155175
}
156-
return b.cacheFromGVK(list.GetObjectKind().GroupVersionKind()).List(ctx, list, opts...)
176+
177+
cache, err := b.cacheFromGVK(list.GetObjectKind().GroupVersionKind())
178+
if err != nil {
179+
return err
180+
}
181+
return cache.List(ctx, list, opts...)
157182
}
158183

159184
// cacheFromGVK returns either the cluster or namespaced cache, based on the
160185
// resource type given.
161-
func (b *multiScopedCache) cacheFromGVK(gvk schema.GroupVersionKind) cache.Cache {
186+
func (b *multiScopedCache) cacheFromGVK(gvk schema.GroupVersionKind) (cache.Cache, error) {
162187
if gvk.Group == "" && gvk.Kind == "" {
163-
panic("The Group and/or Kind must be set")
188+
return nil, fmt.Errorf("the Group and/or Kind must be set")
164189
}
165190

166191
for _, namespacedInformer := range b.namespacedInformers {
167192
if namespacedInformer.Group == gvk.Group && namespacedInformer.Kind == gvk.Kind {
168-
return b.namespacedCache
193+
return b.namespacedCache, nil
169194
}
170195
}
171-
return b.clusterCache
196+
return b.clusterCache, nil
172197
}
173198

174199
// setGroupVersionKind populates the Group and Kind fields of obj using the

pkg/bundle/controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import (
3838
"sigs.k8s.io/controller-runtime/pkg/source"
3939

4040
trustapi "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1"
41-
"github.com/cert-manager/trust-manager/pkg/bundle/internal"
41+
multiscopedcache "github.com/cert-manager/trust-manager/pkg/bundle/cache"
4242
"github.com/cert-manager/trust-manager/pkg/fspkg"
4343
)
4444

@@ -196,5 +196,5 @@ func (b *bundle) mustBundleList(ctx context.Context) *trustapi.BundleList {
196196
// NewCacheFunc will return a multi-scoped controller-runtime NewCacheFunc
197197
// where Secret resources will only be watched within the trust Namespace.
198198
func NewCacheFunc(scheme *runtime.Scheme, opts Options) cache.NewCacheFunc {
199-
return internal.NewMultiScopedCache(scheme, opts.Namespace, []schema.GroupKind{{Kind: "Secret"}})
199+
return multiscopedcache.NewMultiScopedCache(scheme, opts.Namespace, []schema.GroupKind{{Kind: "Secret"}})
200200
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
Copyright 2021 The cert-manager 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 test
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"testing"
23+
"time"
24+
25+
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
27+
corev1 "k8s.io/api/core/v1"
28+
rbacv1 "k8s.io/api/rbac/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/runtime"
31+
"k8s.io/apimachinery/pkg/runtime/schema"
32+
"k8s.io/client-go/rest"
33+
"sigs.k8s.io/controller-runtime/pkg/cache"
34+
"sigs.k8s.io/controller-runtime/pkg/client"
35+
"sigs.k8s.io/controller-runtime/pkg/envtest"
36+
37+
multiscopedcache "github.com/cert-manager/trust-manager/pkg/bundle/cache"
38+
)
39+
40+
func TestCache(t *testing.T) {
41+
env := &envtest.Environment{}
42+
43+
_, err := env.Start()
44+
require.NoError(t, err)
45+
defer func() {
46+
err := env.Stop()
47+
require.NoError(t, err)
48+
}()
49+
50+
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
51+
defer cancel()
52+
53+
namespace := "test-namespace"
54+
55+
// Create a service account that can only retrieve secrets in a single namespace.
56+
var cacheRestConfig *rest.Config
57+
{
58+
godClient, err := client.New(env.Config, client.Options{})
59+
require.NoError(t, err)
60+
61+
ns := &corev1.Namespace{
62+
ObjectMeta: metav1.ObjectMeta{
63+
Name: namespace,
64+
},
65+
}
66+
err = godClient.Create(ctx, ns)
67+
require.NoError(t, err)
68+
69+
sa := &corev1.ServiceAccount{
70+
ObjectMeta: metav1.ObjectMeta{
71+
Name: "cache-sa",
72+
Namespace: namespace,
73+
},
74+
}
75+
err = godClient.Create(ctx, sa)
76+
require.NoError(t, err)
77+
78+
role := &rbacv1.Role{
79+
ObjectMeta: metav1.ObjectMeta{
80+
Name: "cache-role",
81+
Namespace: namespace,
82+
},
83+
Rules: []rbacv1.PolicyRule{
84+
{
85+
Verbs: []string{"list", "watch"},
86+
APIGroups: []string{""},
87+
Resources: []string{"secrets"},
88+
},
89+
},
90+
}
91+
err = godClient.Create(ctx, role)
92+
require.NoError(t, err)
93+
94+
rolebinding := rbacv1.RoleBinding{
95+
ObjectMeta: metav1.ObjectMeta{
96+
Name: "cache-rolebinding",
97+
Namespace: namespace,
98+
},
99+
RoleRef: rbacv1.RoleRef{
100+
APIGroup: "rbac.authorization.k8s.io",
101+
Kind: "Role",
102+
Name: "cache-role",
103+
},
104+
Subjects: []rbacv1.Subject{
105+
{
106+
Kind: "ServiceAccount",
107+
Name: "cache-sa",
108+
Namespace: namespace,
109+
},
110+
},
111+
}
112+
err = godClient.Create(ctx, &rolebinding)
113+
require.NoError(t, err)
114+
115+
// Create a config that uses the service account.
116+
cacheRestConfig = rest.CopyConfig(env.Config)
117+
cacheRestConfig.Impersonate.UserName = fmt.Sprintf("system:serviceaccount:%s:%s", namespace, "cache-sa")
118+
cacheRestConfig.Impersonate.UID = string(sa.UID)
119+
120+
// Create a secret that the service account can access.
121+
secret := &corev1.Secret{
122+
ObjectMeta: metav1.ObjectMeta{
123+
Name: "test-secret",
124+
Namespace: namespace,
125+
},
126+
Data: map[string][]byte{
127+
"test": []byte("test"),
128+
},
129+
}
130+
err = godClient.Create(ctx, secret)
131+
require.NoError(t, err)
132+
}
133+
134+
scheme := runtime.NewScheme()
135+
require.NoError(t, corev1.AddToScheme(scheme))
136+
newCache := multiscopedcache.NewMultiScopedCache(scheme, namespace, []schema.GroupKind{{Group: "", Kind: "Secret"}})
137+
138+
cache, err := newCache(cacheRestConfig, cache.Options{})
139+
require.NoError(t, err)
140+
141+
done := make(chan error)
142+
go func() {
143+
done <- cache.Start(ctx)
144+
}()
145+
defer func() {
146+
require.NoError(t, <-done)
147+
}()
148+
149+
assert.True(t, cache.WaitForCacheSync(ctx), "failed to sync cache")
150+
151+
secret := &corev1.Secret{}
152+
err = cache.Get(ctx, client.ObjectKey{
153+
Namespace: namespace,
154+
Name: "test-secret",
155+
}, secret)
156+
require.NoError(t, err)
157+
158+
require.Equal(t, []byte("test"), secret.Data["test"])
159+
}

0 commit comments

Comments
 (0)