Skip to content

Commit 3cacf4a

Browse files
committed
add test for transformer
1 parent 68f63b4 commit 3cacf4a

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

pkg/cache/cache_test.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"reflect"
2323
"sort"
2424
"strconv"
25+
"time"
2526

2627
. "github.com/onsi/ginkgo"
2728
. "github.com/onsi/ginkgo/extensions/table"
@@ -121,6 +122,237 @@ var _ = Describe("Multi-Namespace Informer Cache", func() {
121122
var _ = Describe("Informer Cache without DeepCopy", func() {
122123
CacheTest(cache.New, cache.Options{UnsafeDisableDeepCopyByObject: cache.DisableDeepCopyByObject{cache.ObjectAll{}: true}})
123124
})
125+
126+
var _ = Describe("Cache with transformers", func() {
127+
var (
128+
informerCache cache.Cache
129+
informerCacheCtx context.Context
130+
informerCacheCancel context.CancelFunc
131+
clien client.Client
132+
transformerHits map[string]int
133+
)
134+
135+
pod := &corev1.Pod{
136+
TypeMeta: metav1.TypeMeta{},
137+
ObjectMeta: metav1.ObjectMeta{
138+
Name: "test.pod",
139+
Namespace: testNamespaceOne,
140+
},
141+
Spec: corev1.PodSpec{
142+
Containers: []corev1.Container{
143+
{
144+
Name: "my-cool-container",
145+
Image: "nginx",
146+
},
147+
},
148+
},
149+
Status: corev1.PodStatus{},
150+
}
151+
pod.SetGroupVersionKind(schema.GroupVersionKind{
152+
Kind: "Pod",
153+
Version: "v1",
154+
})
155+
156+
BeforeEach(func() {
157+
var err error
158+
var transform = func(s string, i interface{}) (interface{}, error) {
159+
if obj, ok := i.(client.Object); ok {
160+
annos := obj.GetAnnotations()
161+
if annos == nil {
162+
annos = map[string]string{}
163+
}
164+
165+
k := "gotype"
166+
167+
// If the key does not exist, then this is the first time the
168+
// object is being transformed. Therefore it is safe to modify
169+
// the instance directly without copying
170+
if _, exists := annos[k]; !exists {
171+
typ := reflect.TypeOf(i)
172+
for typ.Kind() == reflect.Ptr {
173+
typ = typ.Elem()
174+
}
175+
annos[k] = typ.PkgPath() + "." + typ.Name()
176+
obj.SetAnnotations(annos)
177+
}
178+
}
179+
180+
if transformerHits == nil {
181+
transformerHits = map[string]int{}
182+
}
183+
184+
if exist, ok := transformerHits[s]; ok {
185+
transformerHits[s] = exist + 1
186+
} else {
187+
transformerHits[s] = 1
188+
}
189+
return i, nil
190+
}
191+
192+
clien, err = client.New(cfg, client.Options{})
193+
Expect(err).NotTo(HaveOccurred())
194+
err = ensureNamespace(testNamespaceOne, clien)
195+
Expect(err).NotTo(HaveOccurred())
196+
197+
pod := pod.DeepCopy()
198+
199+
unstructuredPod := &unstructured.Unstructured{}
200+
unstructuredPod.SetGroupVersionKind(pod.GroupVersionKind())
201+
202+
metadataPod := &metav1.PartialObjectMetadata{}
203+
metadataPod.SetGroupVersionKind(pod.GroupVersionKind())
204+
205+
By("creating the informer cache")
206+
informerCache, err = cache.New(cfg, cache.Options{
207+
TransformFuncByObject: cache.TransformFuncByObject{
208+
unstructuredPod: func(i interface{}) (interface{}, error) {
209+
return transform("unstructured", i)
210+
},
211+
metadataPod: func(i interface{}) (interface{}, error) {
212+
return transform("metadata", i)
213+
},
214+
pod: func(i interface{}) (interface{}, error) {
215+
return transform("structured", i)
216+
},
217+
},
218+
})
219+
Expect(err).NotTo(HaveOccurred())
220+
221+
informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background())
222+
Expect(cfg).NotTo(BeNil())
223+
224+
err = clien.Create(informerCacheCtx, pod)
225+
Expect(err).ToNot(HaveOccurred())
226+
227+
By("running the cache")
228+
go func(ctx context.Context) {
229+
defer GinkgoRecover()
230+
Expect(informerCache.Start(ctx)).To(Succeed())
231+
}(informerCacheCtx)
232+
Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
233+
})
234+
235+
AfterEach(func() {
236+
unstructuredPod := &unstructured.Unstructured{}
237+
unstructuredPod.SetGroupVersionKind(pod.GroupVersionKind())
238+
unstructuredPod.SetName("test.pod")
239+
unstructuredPod.SetNamespace(pod.Namespace)
240+
241+
clien.Delete(informerCacheCtx, unstructuredPod)
242+
informerCacheCancel()
243+
})
244+
245+
It("should transform unstructured objects", func() {
246+
By("making sure transform is applied to initial cache listing")
247+
podsList := &unstructured.UnstructuredList{
248+
Object: map[string]interface{}{
249+
"apiVersion": "v1",
250+
"kind": "PodList",
251+
},
252+
}
253+
254+
err := informerCache.List(informerCacheCtx, podsList)
255+
Expect(err).ToNot(HaveOccurred())
256+
257+
// Make sure transformer is applied on create
258+
Expect(transformerHits["unstructured"]).To(Equal(1))
259+
260+
By("making sure transform is applied to updated cache listings")
261+
unstructuredPod := &podsList.Items[0]
262+
unstructuredPod.SetAnnotations(map[string]string{
263+
"test": "hello",
264+
})
265+
266+
err = clien.Update(informerCacheCtx, unstructuredPod)
267+
Expect(err).ToNot(HaveOccurred())
268+
269+
podsList = &unstructured.UnstructuredList{
270+
Object: map[string]interface{}{
271+
"apiVersion": "v1",
272+
"kind": "PodList",
273+
},
274+
}
275+
276+
err = informerCache.List(informerCacheCtx, podsList)
277+
Expect(err).ToNot(HaveOccurred())
278+
279+
//!TODO: I do not know a way to force the underlying listerwatcher
280+
// to update. Please advise. Sleep here temporarily since it is required
281+
// to reliably pass.
282+
time.Sleep(1 * time.Second)
283+
Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
284+
Expect(transformerHits["unstructured"]).To(Equal(2))
285+
})
286+
It("should transform structured objects", func() {
287+
podsList := &corev1.PodList{}
288+
err := informerCache.List(informerCacheCtx, podsList)
289+
Expect(err).ToNot(HaveOccurred())
290+
291+
// Make sure transformer is applied on create
292+
Expect(transformerHits["structured"]).To(Equal(1))
293+
294+
By("making sure transform is applied to updated cache listings")
295+
pod := &podsList.Items[0]
296+
pod.SetAnnotations(map[string]string{
297+
"test": "hello",
298+
})
299+
300+
err = clien.Update(informerCacheCtx, pod)
301+
Expect(err).ToNot(HaveOccurred())
302+
303+
podsList = &corev1.PodList{}
304+
err = informerCache.List(informerCacheCtx, podsList)
305+
Expect(err).ToNot(HaveOccurred())
306+
307+
//!TODO: I do not know a way to force the underlying listerwatcher
308+
// to update. Please advise. Sleep here temporarily since it is required
309+
// to reliably pass.
310+
time.Sleep(1 * time.Second)
311+
Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
312+
Expect(transformerHits["structured"]).To(Equal(2))
313+
})
314+
It("should transform metadata objects", func() {
315+
podsList := &metav1.PartialObjectMetadataList{
316+
TypeMeta: metav1.TypeMeta{
317+
APIVersion: "v1",
318+
Kind: "PodList",
319+
},
320+
}
321+
322+
err := informerCache.List(informerCacheCtx, podsList)
323+
Expect(err).ToNot(HaveOccurred())
324+
325+
// Make sure transformer is applied on create
326+
Expect(transformerHits["metadata"]).To(Equal(1))
327+
328+
By("making sure transform is applied to updated cache listings")
329+
pod := pod.DeepCopy()
330+
pod.SetAnnotations(map[string]string{
331+
"test": "hello",
332+
})
333+
334+
err = clien.Update(informerCacheCtx, pod)
335+
Expect(err).ToNot(HaveOccurred())
336+
337+
podsList = &metav1.PartialObjectMetadataList{
338+
TypeMeta: metav1.TypeMeta{
339+
APIVersion: "v1",
340+
Kind: "PodList",
341+
},
342+
}
343+
344+
err = informerCache.List(informerCacheCtx, podsList)
345+
Expect(err).ToNot(HaveOccurred())
346+
347+
//!TODO: I do not know a way to force the underlying listerwatcher
348+
// to update. Please advise. Sleep here temporarily since it is required
349+
// to reliably pass.
350+
time.Sleep(1 * time.Second)
351+
Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
352+
Expect(transformerHits["metadata"]).To(Equal(2))
353+
})
354+
})
355+
124356
var _ = Describe("Cache with selectors", func() {
125357
defer GinkgoRecover()
126358
var (

0 commit comments

Comments
 (0)