...

Source file src/k8s.io/client-go/metadata/metadatainformer/informer_test.go

Documentation: k8s.io/client-go/metadata/metadatainformer

     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 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  		// scenario 1
    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  		// scenario 2
    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  		// scenario 3
   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  			// test data
   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  			// act
   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