...

Source file src/k8s.io/client-go/metadata/fake/simple.go

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

     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 fake
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/labels"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"k8s.io/apimachinery/pkg/runtime/serializer"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	"k8s.io/apimachinery/pkg/watch"
    32  	"k8s.io/client-go/metadata"
    33  	"k8s.io/client-go/testing"
    34  )
    35  
    36  // MetadataClient assists in creating fake objects for use when testing, since metadata.Getter
    37  // does not expose create
    38  type MetadataClient interface {
    39  	metadata.Getter
    40  	CreateFake(obj *metav1.PartialObjectMetadata, opts metav1.CreateOptions, subresources ...string) (*metav1.PartialObjectMetadata, error)
    41  	UpdateFake(obj *metav1.PartialObjectMetadata, opts metav1.UpdateOptions, subresources ...string) (*metav1.PartialObjectMetadata, error)
    42  }
    43  
    44  // NewTestScheme creates a unique Scheme for each test.
    45  func NewTestScheme() *runtime.Scheme {
    46  	return runtime.NewScheme()
    47  }
    48  
    49  // NewSimpleMetadataClient creates a new client that will use the provided scheme and respond with the
    50  // provided objects when requests are made. It will track actions made to the client which can be checked
    51  // with GetActions().
    52  func NewSimpleMetadataClient(scheme *runtime.Scheme, objects ...runtime.Object) *FakeMetadataClient {
    53  	gvkFakeList := schema.GroupVersionKind{Group: "fake-metadata-client-group", Version: "v1", Kind: "List"}
    54  	if !scheme.Recognizes(gvkFakeList) {
    55  		// In order to use List with this client, you have to have the v1.List registered in your scheme, since this is a test
    56  		// type we modify the input scheme
    57  		scheme.AddKnownTypeWithName(gvkFakeList, &metav1.List{})
    58  	}
    59  
    60  	codecs := serializer.NewCodecFactory(scheme)
    61  	o := testing.NewObjectTracker(scheme, codecs.UniversalDeserializer())
    62  	for _, obj := range objects {
    63  		if err := o.Add(obj); err != nil {
    64  			panic(err)
    65  		}
    66  	}
    67  
    68  	cs := &FakeMetadataClient{scheme: scheme, tracker: o}
    69  	cs.AddReactor("*", "*", testing.ObjectReaction(o))
    70  	cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
    71  		gvr := action.GetResource()
    72  		ns := action.GetNamespace()
    73  		watch, err := o.Watch(gvr, ns)
    74  		if err != nil {
    75  			return false, nil, err
    76  		}
    77  		return true, watch, nil
    78  	})
    79  
    80  	return cs
    81  }
    82  
    83  // FakeMetadataClient implements clientset.Interface. Meant to be embedded into a
    84  // struct to get a default implementation. This makes faking out just the method
    85  // you want to test easier.
    86  type FakeMetadataClient struct {
    87  	testing.Fake
    88  	scheme  *runtime.Scheme
    89  	tracker testing.ObjectTracker
    90  }
    91  
    92  type metadataResourceClient struct {
    93  	client    *FakeMetadataClient
    94  	namespace string
    95  	resource  schema.GroupVersionResource
    96  }
    97  
    98  var (
    99  	_ metadata.Interface = &FakeMetadataClient{}
   100  	_ testing.FakeClient = &FakeMetadataClient{}
   101  )
   102  
   103  func (c *FakeMetadataClient) Tracker() testing.ObjectTracker {
   104  	return c.tracker
   105  }
   106  
   107  // Resource returns an interface for accessing the provided resource.
   108  func (c *FakeMetadataClient) Resource(resource schema.GroupVersionResource) metadata.Getter {
   109  	return &metadataResourceClient{client: c, resource: resource}
   110  }
   111  
   112  // Namespace returns an interface for accessing the current resource in the specified
   113  // namespace.
   114  func (c *metadataResourceClient) Namespace(ns string) metadata.ResourceInterface {
   115  	ret := *c
   116  	ret.namespace = ns
   117  	return &ret
   118  }
   119  
   120  // CreateFake records the object creation and processes it via the reactor.
   121  func (c *metadataResourceClient) CreateFake(obj *metav1.PartialObjectMetadata, opts metav1.CreateOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
   122  	var uncastRet runtime.Object
   123  	var err error
   124  	switch {
   125  	case len(c.namespace) == 0 && len(subresources) == 0:
   126  		uncastRet, err = c.client.Fake.
   127  			Invokes(testing.NewRootCreateAction(c.resource, obj), obj)
   128  
   129  	case len(c.namespace) == 0 && len(subresources) > 0:
   130  		var accessor metav1.Object // avoid shadowing err
   131  		accessor, err = meta.Accessor(obj)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  		name := accessor.GetName()
   136  		uncastRet, err = c.client.Fake.
   137  			Invokes(testing.NewRootCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), obj), obj)
   138  
   139  	case len(c.namespace) > 0 && len(subresources) == 0:
   140  		uncastRet, err = c.client.Fake.
   141  			Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj)
   142  
   143  	case len(c.namespace) > 0 && len(subresources) > 0:
   144  		var accessor metav1.Object // avoid shadowing err
   145  		accessor, err = meta.Accessor(obj)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  		name := accessor.GetName()
   150  		uncastRet, err = c.client.Fake.
   151  			Invokes(testing.NewCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), c.namespace, obj), obj)
   152  
   153  	}
   154  
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	if uncastRet == nil {
   159  		return nil, err
   160  	}
   161  	ret, ok := uncastRet.(*metav1.PartialObjectMetadata)
   162  	if !ok {
   163  		return nil, fmt.Errorf("unexpected return value type %T", uncastRet)
   164  	}
   165  	return ret, err
   166  }
   167  
   168  // UpdateFake records the object update and processes it via the reactor.
   169  func (c *metadataResourceClient) UpdateFake(obj *metav1.PartialObjectMetadata, opts metav1.UpdateOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
   170  	var uncastRet runtime.Object
   171  	var err error
   172  	switch {
   173  	case len(c.namespace) == 0 && len(subresources) == 0:
   174  		uncastRet, err = c.client.Fake.
   175  			Invokes(testing.NewRootUpdateAction(c.resource, obj), obj)
   176  
   177  	case len(c.namespace) == 0 && len(subresources) > 0:
   178  		uncastRet, err = c.client.Fake.
   179  			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), obj), obj)
   180  
   181  	case len(c.namespace) > 0 && len(subresources) == 0:
   182  		uncastRet, err = c.client.Fake.
   183  			Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj)
   184  
   185  	case len(c.namespace) > 0 && len(subresources) > 0:
   186  		uncastRet, err = c.client.Fake.
   187  			Invokes(testing.NewUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, obj), obj)
   188  
   189  	}
   190  
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	if uncastRet == nil {
   195  		return nil, err
   196  	}
   197  	ret, ok := uncastRet.(*metav1.PartialObjectMetadata)
   198  	if !ok {
   199  		return nil, fmt.Errorf("unexpected return value type %T", uncastRet)
   200  	}
   201  	return ret, err
   202  }
   203  
   204  // UpdateStatus records the object status update and processes it via the reactor.
   205  func (c *metadataResourceClient) UpdateStatus(obj *metav1.PartialObjectMetadata, opts metav1.UpdateOptions) (*metav1.PartialObjectMetadata, error) {
   206  	var uncastRet runtime.Object
   207  	var err error
   208  	switch {
   209  	case len(c.namespace) == 0:
   210  		uncastRet, err = c.client.Fake.
   211  			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, "status", obj), obj)
   212  
   213  	case len(c.namespace) > 0:
   214  		uncastRet, err = c.client.Fake.
   215  			Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj)
   216  
   217  	}
   218  
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	if uncastRet == nil {
   223  		return nil, err
   224  	}
   225  	ret, ok := uncastRet.(*metav1.PartialObjectMetadata)
   226  	if !ok {
   227  		return nil, fmt.Errorf("unexpected return value type %T", uncastRet)
   228  	}
   229  	return ret, err
   230  }
   231  
   232  // Delete records the object deletion and processes it via the reactor.
   233  func (c *metadataResourceClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error {
   234  	var err error
   235  	switch {
   236  	case len(c.namespace) == 0 && len(subresources) == 0:
   237  		_, err = c.client.Fake.
   238  			Invokes(testing.NewRootDeleteAction(c.resource, name), &metav1.Status{Status: "metadata delete fail"})
   239  
   240  	case len(c.namespace) == 0 && len(subresources) > 0:
   241  		_, err = c.client.Fake.
   242  			Invokes(testing.NewRootDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "metadata delete fail"})
   243  
   244  	case len(c.namespace) > 0 && len(subresources) == 0:
   245  		_, err = c.client.Fake.
   246  			Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "metadata delete fail"})
   247  
   248  	case len(c.namespace) > 0 && len(subresources) > 0:
   249  		_, err = c.client.Fake.
   250  			Invokes(testing.NewDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, name), &metav1.Status{Status: "metadata delete fail"})
   251  	}
   252  
   253  	return err
   254  }
   255  
   256  // DeleteCollection records the object collection deletion and processes it via the reactor.
   257  func (c *metadataResourceClient) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error {
   258  	var err error
   259  	switch {
   260  	case len(c.namespace) == 0:
   261  		action := testing.NewRootDeleteCollectionAction(c.resource, listOptions)
   262  		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "metadata deletecollection fail"})
   263  
   264  	case len(c.namespace) > 0:
   265  		action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions)
   266  		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "metadata deletecollection fail"})
   267  
   268  	}
   269  
   270  	return err
   271  }
   272  
   273  // Get records the object retrieval and processes it via the reactor.
   274  func (c *metadataResourceClient) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
   275  	var uncastRet runtime.Object
   276  	var err error
   277  	switch {
   278  	case len(c.namespace) == 0 && len(subresources) == 0:
   279  		uncastRet, err = c.client.Fake.
   280  			Invokes(testing.NewRootGetAction(c.resource, name), &metav1.Status{Status: "metadata get fail"})
   281  
   282  	case len(c.namespace) == 0 && len(subresources) > 0:
   283  		uncastRet, err = c.client.Fake.
   284  			Invokes(testing.NewRootGetSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "metadata get fail"})
   285  
   286  	case len(c.namespace) > 0 && len(subresources) == 0:
   287  		uncastRet, err = c.client.Fake.
   288  			Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "metadata get fail"})
   289  
   290  	case len(c.namespace) > 0 && len(subresources) > 0:
   291  		uncastRet, err = c.client.Fake.
   292  			Invokes(testing.NewGetSubresourceAction(c.resource, c.namespace, strings.Join(subresources, "/"), name), &metav1.Status{Status: "metadata get fail"})
   293  	}
   294  
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	if uncastRet == nil {
   299  		return nil, err
   300  	}
   301  	ret, ok := uncastRet.(*metav1.PartialObjectMetadata)
   302  	if !ok {
   303  		return nil, fmt.Errorf("unexpected return value type %T", uncastRet)
   304  	}
   305  	return ret, err
   306  }
   307  
   308  // List records the object deletion and processes it via the reactor.
   309  func (c *metadataResourceClient) List(ctx context.Context, opts metav1.ListOptions) (*metav1.PartialObjectMetadataList, error) {
   310  	var obj runtime.Object
   311  	var err error
   312  	switch {
   313  	case len(c.namespace) == 0:
   314  		obj, err = c.client.Fake.
   315  			Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Group: "fake-metadata-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, opts), &metav1.Status{Status: "metadata list fail"})
   316  
   317  	case len(c.namespace) > 0:
   318  		obj, err = c.client.Fake.
   319  			Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Group: "fake-metadata-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, c.namespace, opts), &metav1.Status{Status: "metadata list fail"})
   320  
   321  	}
   322  
   323  	if obj == nil {
   324  		return nil, err
   325  	}
   326  
   327  	label, _, _ := testing.ExtractFromListOptions(opts)
   328  	if label == nil {
   329  		label = labels.Everything()
   330  	}
   331  
   332  	inputList, ok := obj.(*metav1.List)
   333  	if !ok {
   334  		return nil, fmt.Errorf("incoming object is incorrect type %T", obj)
   335  	}
   336  
   337  	list := &metav1.PartialObjectMetadataList{
   338  		ListMeta: inputList.ListMeta,
   339  	}
   340  	for i := range inputList.Items {
   341  		item, ok := inputList.Items[i].Object.(*metav1.PartialObjectMetadata)
   342  		if !ok {
   343  			return nil, fmt.Errorf("item %d in list %T is %T", i, inputList, inputList.Items[i].Object)
   344  		}
   345  		metadata, err := meta.Accessor(item)
   346  		if err != nil {
   347  			return nil, err
   348  		}
   349  		if label.Matches(labels.Set(metadata.GetLabels())) {
   350  			list.Items = append(list.Items, *item)
   351  		}
   352  	}
   353  	return list, nil
   354  }
   355  
   356  func (c *metadataResourceClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
   357  	switch {
   358  	case len(c.namespace) == 0:
   359  		return c.client.Fake.
   360  			InvokesWatch(testing.NewRootWatchAction(c.resource, opts))
   361  
   362  	case len(c.namespace) > 0:
   363  		return c.client.Fake.
   364  			InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts))
   365  
   366  	}
   367  
   368  	panic("math broke")
   369  }
   370  
   371  // Patch records the object patch and processes it via the reactor.
   372  func (c *metadataResourceClient) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
   373  	var uncastRet runtime.Object
   374  	var err error
   375  	switch {
   376  	case len(c.namespace) == 0 && len(subresources) == 0:
   377  		uncastRet, err = c.client.Fake.
   378  			Invokes(testing.NewRootPatchAction(c.resource, name, pt, data), &metav1.Status{Status: "metadata patch fail"})
   379  
   380  	case len(c.namespace) == 0 && len(subresources) > 0:
   381  		uncastRet, err = c.client.Fake.
   382  			Invokes(testing.NewRootPatchSubresourceAction(c.resource, name, pt, data, subresources...), &metav1.Status{Status: "metadata patch fail"})
   383  
   384  	case len(c.namespace) > 0 && len(subresources) == 0:
   385  		uncastRet, err = c.client.Fake.
   386  			Invokes(testing.NewPatchAction(c.resource, c.namespace, name, pt, data), &metav1.Status{Status: "metadata patch fail"})
   387  
   388  	case len(c.namespace) > 0 && len(subresources) > 0:
   389  		uncastRet, err = c.client.Fake.
   390  			Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, pt, data, subresources...), &metav1.Status{Status: "metadata patch fail"})
   391  
   392  	}
   393  
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	if uncastRet == nil {
   398  		return nil, err
   399  	}
   400  	ret, ok := uncastRet.(*metav1.PartialObjectMetadata)
   401  	if !ok {
   402  		return nil, fmt.Errorf("unexpected return value type %T", uncastRet)
   403  	}
   404  	return ret, err
   405  }
   406  

View as plain text