1
16
17 package metadatainformer
18
19 import (
20 "context"
21 "flag"
22 "testing"
23 "time"
24
25 "github.com/google/go-cmp/cmp"
26 "k8s.io/klog/v2"
27
28 "k8s.io/apimachinery/pkg/api/equality"
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/metadata/fake"
33 "k8s.io/client-go/tools/cache"
34 )
35
36 func init() {
37 klog.InitFlags(flag.CommandLine)
38 flag.CommandLine.Lookup("v").Value.Set("5")
39 flag.CommandLine.Lookup("alsologtostderr").Value.Set("true")
40 }
41
42 func TestMetadataSharedInformerFactory(t *testing.T) {
43 scenarios := []struct {
44 name string
45 existingObj *metav1.PartialObjectMetadata
46 gvr schema.GroupVersionResource
47 ns string
48 trigger func(gvr schema.GroupVersionResource, ns string, fakeClient *fake.FakeMetadataClient, testObject *metav1.PartialObjectMetadata) *metav1.PartialObjectMetadata
49 handler func(rcvCh chan<- *metav1.PartialObjectMetadata) *cache.ResourceEventHandlerFuncs
50 }{
51
52 {
53 name: "scenario 1: test if adding an object triggers AddFunc",
54 ns: "ns-foo",
55 gvr: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
56 trigger: func(gvr schema.GroupVersionResource, ns string, fakeClient *fake.FakeMetadataClient, _ *metav1.PartialObjectMetadata) *metav1.PartialObjectMetadata {
57 testObject := newPartialObjectMetadata("extensions/v1beta1", "Deployment", "ns-foo", "name-foo")
58 createdObj, err := fakeClient.Resource(gvr).Namespace(ns).(fake.MetadataClient).CreateFake(testObject, metav1.CreateOptions{})
59 if err != nil {
60 t.Error(err)
61 }
62 return createdObj
63 },
64 handler: func(rcvCh chan<- *metav1.PartialObjectMetadata) *cache.ResourceEventHandlerFuncs {
65 return &cache.ResourceEventHandlerFuncs{
66 AddFunc: func(obj interface{}) {
67 rcvCh <- obj.(*metav1.PartialObjectMetadata)
68 },
69 }
70 },
71 },
72
73
74 {
75 name: "scenario 2: tests if updating an object triggers UpdateFunc",
76 ns: "ns-foo",
77 gvr: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
78 existingObj: newPartialObjectMetadata("extensions/v1beta1", "Deployment", "ns-foo", "name-foo"),
79 trigger: func(gvr schema.GroupVersionResource, ns string, fakeClient *fake.FakeMetadataClient, testObject *metav1.PartialObjectMetadata) *metav1.PartialObjectMetadata {
80 if testObject.Annotations == nil {
81 testObject.Annotations = make(map[string]string)
82 }
83 testObject.Annotations["test"] = "updatedName"
84 updatedObj, err := fakeClient.Resource(gvr).Namespace(ns).(fake.MetadataClient).UpdateFake(testObject, metav1.UpdateOptions{})
85 if err != nil {
86 t.Error(err)
87 }
88 return updatedObj
89 },
90 handler: func(rcvCh chan<- *metav1.PartialObjectMetadata) *cache.ResourceEventHandlerFuncs {
91 return &cache.ResourceEventHandlerFuncs{
92 UpdateFunc: func(old, updated interface{}) {
93 rcvCh <- updated.(*metav1.PartialObjectMetadata)
94 },
95 }
96 },
97 },
98
99
100 {
101 name: "scenario 3: test if deleting an object triggers DeleteFunc",
102 ns: "ns-foo",
103 gvr: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"},
104 existingObj: newPartialObjectMetadata("extensions/v1beta1", "Deployment", "ns-foo", "name-foo"),
105 trigger: func(gvr schema.GroupVersionResource, ns string, fakeClient *fake.FakeMetadataClient, testObject *metav1.PartialObjectMetadata) *metav1.PartialObjectMetadata {
106 err := fakeClient.Resource(gvr).Namespace(ns).Delete(context.TODO(), testObject.GetName(), metav1.DeleteOptions{})
107 if err != nil {
108 t.Error(err)
109 }
110 return testObject
111 },
112 handler: func(rcvCh chan<- *metav1.PartialObjectMetadata) *cache.ResourceEventHandlerFuncs {
113 return &cache.ResourceEventHandlerFuncs{
114 DeleteFunc: func(obj interface{}) {
115 rcvCh <- obj.(*metav1.PartialObjectMetadata)
116 },
117 }
118 },
119 },
120 }
121
122 for _, ts := range scenarios {
123 t.Run(ts.name, func(t *testing.T) {
124
125 timeout := time.Duration(3 * time.Second)
126 ctx, cancel := context.WithTimeout(context.Background(), timeout)
127 defer cancel()
128 scheme := fake.NewTestScheme()
129 metav1.AddMetaToScheme(scheme)
130 informerReciveObjectCh := make(chan *metav1.PartialObjectMetadata, 1)
131 objs := []runtime.Object{}
132 if ts.existingObj != nil {
133 objs = append(objs, ts.existingObj)
134 }
135 fakeClient := fake.NewSimpleMetadataClient(scheme, objs...)
136 target := NewSharedInformerFactory(fakeClient, 0)
137
138
139 informerListerForGvr := target.ForResource(ts.gvr)
140 informerListerForGvr.Informer().AddEventHandler(ts.handler(informerReciveObjectCh))
141 target.Start(ctx.Done())
142 if synced := target.WaitForCacheSync(ctx.Done()); !synced[ts.gvr] {
143 t.Fatalf("informer for %s hasn't synced", ts.gvr)
144 }
145
146 testObject := ts.trigger(ts.gvr, ts.ns, fakeClient, ts.existingObj)
147 select {
148 case objFromInformer := <-informerReciveObjectCh:
149 if !equality.Semantic.DeepEqual(testObject, objFromInformer) {
150 t.Fatalf("%v", cmp.Diff(testObject, objFromInformer))
151 }
152 case <-ctx.Done():
153 t.Errorf("tested informer haven't received an object, waited %v", timeout)
154 }
155 })
156 }
157 }
158
159 func newPartialObjectMetadata(apiVersion, kind, namespace, name string) *metav1.PartialObjectMetadata {
160 return &metav1.PartialObjectMetadata{
161 TypeMeta: metav1.TypeMeta{
162 APIVersion: apiVersion,
163 Kind: kind,
164 },
165 ObjectMeta: metav1.ObjectMeta{
166 Namespace: namespace,
167 Name: name,
168 },
169 }
170 }
171
View as plain text