From 3cacf4aebb4c287bf1f7d7665aee653c197df8b9 Mon Sep 17 00:00:00 2001 From: Alexander Zielenski <351783+alexzielenski@users.noreply.github.com> Date: Wed, 6 Apr 2022 17:43:04 -0700 Subject: [PATCH] add test for transformer --- pkg/cache/cache_test.go | 232 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go index 07c96b1c24..0dbf0e4a9e 100644 --- a/pkg/cache/cache_test.go +++ b/pkg/cache/cache_test.go @@ -22,6 +22,7 @@ import ( "reflect" "sort" "strconv" + "time" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" @@ -121,6 +122,237 @@ var _ = Describe("Multi-Namespace Informer Cache", func() { var _ = Describe("Informer Cache without DeepCopy", func() { CacheTest(cache.New, cache.Options{UnsafeDisableDeepCopyByObject: cache.DisableDeepCopyByObject{cache.ObjectAll{}: true}}) }) + +var _ = Describe("Cache with transformers", func() { + var ( + informerCache cache.Cache + informerCacheCtx context.Context + informerCacheCancel context.CancelFunc + clien client.Client + transformerHits map[string]int + ) + + pod := &corev1.Pod{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "test.pod", + Namespace: testNamespaceOne, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "my-cool-container", + Image: "nginx", + }, + }, + }, + Status: corev1.PodStatus{}, + } + pod.SetGroupVersionKind(schema.GroupVersionKind{ + Kind: "Pod", + Version: "v1", + }) + + BeforeEach(func() { + var err error + var transform = func(s string, i interface{}) (interface{}, error) { + if obj, ok := i.(client.Object); ok { + annos := obj.GetAnnotations() + if annos == nil { + annos = map[string]string{} + } + + k := "gotype" + + // If the key does not exist, then this is the first time the + // object is being transformed. Therefore it is safe to modify + // the instance directly without copying + if _, exists := annos[k]; !exists { + typ := reflect.TypeOf(i) + for typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + annos[k] = typ.PkgPath() + "." + typ.Name() + obj.SetAnnotations(annos) + } + } + + if transformerHits == nil { + transformerHits = map[string]int{} + } + + if exist, ok := transformerHits[s]; ok { + transformerHits[s] = exist + 1 + } else { + transformerHits[s] = 1 + } + return i, nil + } + + clien, err = client.New(cfg, client.Options{}) + Expect(err).NotTo(HaveOccurred()) + err = ensureNamespace(testNamespaceOne, clien) + Expect(err).NotTo(HaveOccurred()) + + pod := pod.DeepCopy() + + unstructuredPod := &unstructured.Unstructured{} + unstructuredPod.SetGroupVersionKind(pod.GroupVersionKind()) + + metadataPod := &metav1.PartialObjectMetadata{} + metadataPod.SetGroupVersionKind(pod.GroupVersionKind()) + + By("creating the informer cache") + informerCache, err = cache.New(cfg, cache.Options{ + TransformFuncByObject: cache.TransformFuncByObject{ + unstructuredPod: func(i interface{}) (interface{}, error) { + return transform("unstructured", i) + }, + metadataPod: func(i interface{}) (interface{}, error) { + return transform("metadata", i) + }, + pod: func(i interface{}) (interface{}, error) { + return transform("structured", i) + }, + }, + }) + Expect(err).NotTo(HaveOccurred()) + + informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background()) + Expect(cfg).NotTo(BeNil()) + + err = clien.Create(informerCacheCtx, pod) + Expect(err).ToNot(HaveOccurred()) + + By("running the cache") + go func(ctx context.Context) { + defer GinkgoRecover() + Expect(informerCache.Start(ctx)).To(Succeed()) + }(informerCacheCtx) + Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue()) + }) + + AfterEach(func() { + unstructuredPod := &unstructured.Unstructured{} + unstructuredPod.SetGroupVersionKind(pod.GroupVersionKind()) + unstructuredPod.SetName("test.pod") + unstructuredPod.SetNamespace(pod.Namespace) + + clien.Delete(informerCacheCtx, unstructuredPod) + informerCacheCancel() + }) + + It("should transform unstructured objects", func() { + By("making sure transform is applied to initial cache listing") + podsList := &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "PodList", + }, + } + + err := informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + // Make sure transformer is applied on create + Expect(transformerHits["unstructured"]).To(Equal(1)) + + By("making sure transform is applied to updated cache listings") + unstructuredPod := &podsList.Items[0] + unstructuredPod.SetAnnotations(map[string]string{ + "test": "hello", + }) + + err = clien.Update(informerCacheCtx, unstructuredPod) + Expect(err).ToNot(HaveOccurred()) + + podsList = &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "PodList", + }, + } + + err = informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + //!TODO: I do not know a way to force the underlying listerwatcher + // to update. Please advise. Sleep here temporarily since it is required + // to reliably pass. + time.Sleep(1 * time.Second) + Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue()) + Expect(transformerHits["unstructured"]).To(Equal(2)) + }) + It("should transform structured objects", func() { + podsList := &corev1.PodList{} + err := informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + // Make sure transformer is applied on create + Expect(transformerHits["structured"]).To(Equal(1)) + + By("making sure transform is applied to updated cache listings") + pod := &podsList.Items[0] + pod.SetAnnotations(map[string]string{ + "test": "hello", + }) + + err = clien.Update(informerCacheCtx, pod) + Expect(err).ToNot(HaveOccurred()) + + podsList = &corev1.PodList{} + err = informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + //!TODO: I do not know a way to force the underlying listerwatcher + // to update. Please advise. Sleep here temporarily since it is required + // to reliably pass. + time.Sleep(1 * time.Second) + Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue()) + Expect(transformerHits["structured"]).To(Equal(2)) + }) + It("should transform metadata objects", func() { + podsList := &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "PodList", + }, + } + + err := informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + // Make sure transformer is applied on create + Expect(transformerHits["metadata"]).To(Equal(1)) + + By("making sure transform is applied to updated cache listings") + pod := pod.DeepCopy() + pod.SetAnnotations(map[string]string{ + "test": "hello", + }) + + err = clien.Update(informerCacheCtx, pod) + Expect(err).ToNot(HaveOccurred()) + + podsList = &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "PodList", + }, + } + + err = informerCache.List(informerCacheCtx, podsList) + Expect(err).ToNot(HaveOccurred()) + + //!TODO: I do not know a way to force the underlying listerwatcher + // to update. Please advise. Sleep here temporarily since it is required + // to reliably pass. + time.Sleep(1 * time.Second) + Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue()) + Expect(transformerHits["metadata"]).To(Equal(2)) + }) +}) + var _ = Describe("Cache with selectors", func() { defer GinkgoRecover() var (