k8s.io/client-go@v0.31.1/testing/fixture.go (about)

     1  /*
     2  Copyright 2015 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 testing
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"sigs.k8s.io/structured-merge-diff/v4/typed"
    23  	"sigs.k8s.io/yaml"
    24  	"sort"
    25  	"strings"
    26  	"sync"
    27  
    28  	jsonpatch "gopkg.in/evanphx/json-patch.v4"
    29  
    30  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    31  	"k8s.io/apimachinery/pkg/api/meta"
    32  	"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
    33  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    34  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    35  	"k8s.io/apimachinery/pkg/runtime"
    36  	"k8s.io/apimachinery/pkg/runtime/schema"
    37  	"k8s.io/apimachinery/pkg/types"
    38  	"k8s.io/apimachinery/pkg/util/json"
    39  	"k8s.io/apimachinery/pkg/util/managedfields"
    40  	"k8s.io/apimachinery/pkg/util/strategicpatch"
    41  	"k8s.io/apimachinery/pkg/watch"
    42  	restclient "k8s.io/client-go/rest"
    43  )
    44  
    45  // ObjectTracker keeps track of objects. It is intended to be used to
    46  // fake calls to a server by returning objects based on their kind,
    47  // namespace and name.
    48  type ObjectTracker interface {
    49  	// Add adds an object to the tracker. If object being added
    50  	// is a list, its items are added separately.
    51  	Add(obj runtime.Object) error
    52  
    53  	// Get retrieves the object by its kind, namespace and name.
    54  	Get(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.GetOptions) (runtime.Object, error)
    55  
    56  	// Create adds an object to the tracker in the specified namespace.
    57  	Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.CreateOptions) error
    58  
    59  	// Update updates an existing object in the tracker in the specified namespace.
    60  	Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.UpdateOptions) error
    61  
    62  	// Patch patches an existing object in the tracker in the specified namespace.
    63  	Patch(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.PatchOptions) error
    64  
    65  	// Apply applies an object in the tracker in the specified namespace.
    66  	Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, opts ...metav1.PatchOptions) error
    67  
    68  	// List retrieves all objects of a given kind in the given
    69  	// namespace. Only non-List kinds are accepted.
    70  	List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string, opts ...metav1.ListOptions) (runtime.Object, error)
    71  
    72  	// Delete deletes an existing object from the tracker. If object
    73  	// didn't exist in the tracker prior to deletion, Delete returns
    74  	// no error.
    75  	Delete(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.DeleteOptions) error
    76  
    77  	// Watch watches objects from the tracker. Watch returns a channel
    78  	// which will push added / modified / deleted object.
    79  	Watch(gvr schema.GroupVersionResource, ns string, opts ...metav1.ListOptions) (watch.Interface, error)
    80  }
    81  
    82  // ObjectScheme abstracts the implementation of common operations on objects.
    83  type ObjectScheme interface {
    84  	runtime.ObjectCreater
    85  	runtime.ObjectTyper
    86  }
    87  
    88  // ObjectReaction returns a ReactionFunc that applies core.Action to
    89  // the given tracker.
    90  //
    91  // If tracker also implements ManagedFieldObjectTracker, then managed fields
    92  // will be handled by the tracker and apply patch actions will be evaluated
    93  // using the field manager and will take field ownership into consideration.
    94  // Without a ManagedFieldObjectTracker, apply patch actions do not consider
    95  // field ownership.
    96  //
    97  // WARNING: There is no server side defaulting, validation, or conversion handled
    98  // by the fake client and subresources are not handled accurately (fields in the
    99  // root resource are not automatically updated when a scale resource is updated, for example).
   100  func ObjectReaction(tracker ObjectTracker) ReactionFunc {
   101  	reactor := objectTrackerReact{tracker: tracker}
   102  	return func(action Action) (bool, runtime.Object, error) {
   103  		// Here and below we need to switch on implementation types,
   104  		// not on interfaces, as some interfaces are identical
   105  		// (e.g. UpdateAction and CreateAction), so if we use them,
   106  		// updates and creates end up matching the same case branch.
   107  		switch action := action.(type) {
   108  		case ListActionImpl:
   109  			obj, err := reactor.List(action)
   110  			return true, obj, err
   111  		case GetActionImpl:
   112  			obj, err := reactor.Get(action)
   113  			return true, obj, err
   114  		case CreateActionImpl:
   115  			obj, err := reactor.Create(action)
   116  			return true, obj, err
   117  		case UpdateActionImpl:
   118  			obj, err := reactor.Update(action)
   119  			return true, obj, err
   120  		case DeleteActionImpl:
   121  			obj, err := reactor.Delete(action)
   122  			return true, obj, err
   123  		case PatchActionImpl:
   124  			if action.GetPatchType() == types.ApplyPatchType {
   125  				obj, err := reactor.Apply(action)
   126  				return true, obj, err
   127  			}
   128  			obj, err := reactor.Patch(action)
   129  			return true, obj, err
   130  		default:
   131  			return false, nil, fmt.Errorf("no reaction implemented for %s", action)
   132  		}
   133  	}
   134  }
   135  
   136  type objectTrackerReact struct {
   137  	tracker ObjectTracker
   138  }
   139  
   140  func (o objectTrackerReact) List(action ListActionImpl) (runtime.Object, error) {
   141  	return o.tracker.List(action.GetResource(), action.GetKind(), action.GetNamespace(), action.ListOptions)
   142  }
   143  
   144  func (o objectTrackerReact) Get(action GetActionImpl) (runtime.Object, error) {
   145  	return o.tracker.Get(action.GetResource(), action.GetNamespace(), action.GetName(), action.GetOptions)
   146  }
   147  
   148  func (o objectTrackerReact) Create(action CreateActionImpl) (runtime.Object, error) {
   149  	ns := action.GetNamespace()
   150  	gvr := action.GetResource()
   151  	objMeta, err := meta.Accessor(action.GetObject())
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	if action.GetSubresource() == "" {
   156  		err = o.tracker.Create(gvr, action.GetObject(), ns, action.CreateOptions)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  	} else {
   161  		oldObj, getOldObjErr := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   162  		if getOldObjErr != nil {
   163  			return nil, getOldObjErr
   164  		}
   165  		// Check whether the existing historical object type is the same as the current operation object type that needs to be updated, and if it is the same, perform the update operation.
   166  		if reflect.TypeOf(oldObj) == reflect.TypeOf(action.GetObject()) {
   167  			// TODO: Currently we're handling subresource creation as an update
   168  			// on the enclosing resource. This works for some subresources but
   169  			// might not be generic enough.
   170  			err = o.tracker.Update(gvr, action.GetObject(), ns, metav1.UpdateOptions{
   171  				DryRun:          action.CreateOptions.DryRun,
   172  				FieldManager:    action.CreateOptions.FieldManager,
   173  				FieldValidation: action.CreateOptions.FieldValidation,
   174  			})
   175  		} else {
   176  			// If the historical object type is different from the current object type, need to make sure we return the object submitted,don't persist the submitted object in the tracker.
   177  			return action.GetObject(), nil
   178  		}
   179  	}
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	obj, err := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   184  	return obj, err
   185  }
   186  
   187  func (o objectTrackerReact) Update(action UpdateActionImpl) (runtime.Object, error) {
   188  	ns := action.GetNamespace()
   189  	gvr := action.GetResource()
   190  	objMeta, err := meta.Accessor(action.GetObject())
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	err = o.tracker.Update(gvr, action.GetObject(), ns, action.UpdateOptions)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	obj, err := o.tracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   201  	return obj, err
   202  }
   203  
   204  func (o objectTrackerReact) Delete(action DeleteActionImpl) (runtime.Object, error) {
   205  	err := o.tracker.Delete(action.GetResource(), action.GetNamespace(), action.GetName(), action.DeleteOptions)
   206  	return nil, err
   207  }
   208  
   209  func (o objectTrackerReact) Apply(action PatchActionImpl) (runtime.Object, error) {
   210  	ns := action.GetNamespace()
   211  	gvr := action.GetResource()
   212  
   213  	patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
   214  	if err := yaml.Unmarshal(action.GetPatch(), &patchObj.Object); err != nil {
   215  		return nil, err
   216  	}
   217  	err := o.tracker.Apply(gvr, patchObj, ns, action.PatchOptions)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	obj, err := o.tracker.Get(gvr, ns, action.GetName(), metav1.GetOptions{})
   222  	return obj, err
   223  }
   224  
   225  func (o objectTrackerReact) Patch(action PatchActionImpl) (runtime.Object, error) {
   226  	ns := action.GetNamespace()
   227  	gvr := action.GetResource()
   228  
   229  	obj, err := o.tracker.Get(gvr, ns, action.GetName(), metav1.GetOptions{})
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	old, err := json.Marshal(obj)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	// reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields
   240  	// in obj that are removed by patch are cleared
   241  	value := reflect.ValueOf(obj)
   242  	value.Elem().Set(reflect.New(value.Type().Elem()).Elem())
   243  
   244  	switch action.GetPatchType() {
   245  	case types.JSONPatchType:
   246  		patch, err := jsonpatch.DecodePatch(action.GetPatch())
   247  		if err != nil {
   248  			return nil, err
   249  		}
   250  		modified, err := patch.Apply(old)
   251  		if err != nil {
   252  			return nil, err
   253  		}
   254  
   255  		if err = json.Unmarshal(modified, obj); err != nil {
   256  			return nil, err
   257  		}
   258  	case types.MergePatchType:
   259  		modified, err := jsonpatch.MergePatch(old, action.GetPatch())
   260  		if err != nil {
   261  			return nil, err
   262  		}
   263  
   264  		if err := json.Unmarshal(modified, obj); err != nil {
   265  			return nil, err
   266  		}
   267  	case types.StrategicMergePatchType:
   268  		mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj)
   269  		if err != nil {
   270  			return nil, err
   271  		}
   272  		if err = json.Unmarshal(mergedByte, obj); err != nil {
   273  			return nil, err
   274  		}
   275  	default:
   276  		return nil, fmt.Errorf("PatchType %s is not supported", action.GetPatchType())
   277  	}
   278  
   279  	if err = o.tracker.Patch(gvr, obj, ns, action.PatchOptions); err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	return obj, nil
   284  }
   285  
   286  type tracker struct {
   287  	scheme  ObjectScheme
   288  	decoder runtime.Decoder
   289  	lock    sync.RWMutex
   290  	objects map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object
   291  	// The value type of watchers is a map of which the key is either a namespace or
   292  	// all/non namespace aka "" and its value is list of fake watchers.
   293  	// Manipulations on resources will broadcast the notification events into the
   294  	// watchers' channel. Note that too many unhandled events (currently 100,
   295  	// see apimachinery/pkg/watch.DefaultChanSize) will cause a panic.
   296  	watchers map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher
   297  }
   298  
   299  var _ ObjectTracker = &tracker{}
   300  
   301  // NewObjectTracker returns an ObjectTracker that can be used to keep track
   302  // of objects for the fake clientset. Mostly useful for unit tests.
   303  func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker {
   304  	return &tracker{
   305  		scheme:   scheme,
   306  		decoder:  decoder,
   307  		objects:  make(map[schema.GroupVersionResource]map[types.NamespacedName]runtime.Object),
   308  		watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher),
   309  	}
   310  }
   311  
   312  func (t *tracker) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string, opts ...metav1.ListOptions) (runtime.Object, error) {
   313  	_, err := assertOptionalSingleArgument(opts)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	// Heuristic for list kind: original kind + List suffix. Might
   318  	// not always be true but this tracker has a pretty limited
   319  	// understanding of the actual API model.
   320  	listGVK := gvk
   321  	listGVK.Kind = listGVK.Kind + "List"
   322  	// GVK does have the concept of "internal version". The scheme recognizes
   323  	// the runtime.APIVersionInternal, but not the empty string.
   324  	if listGVK.Version == "" {
   325  		listGVK.Version = runtime.APIVersionInternal
   326  	}
   327  
   328  	list, err := t.scheme.New(listGVK)
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  
   333  	if !meta.IsListType(list) {
   334  		return nil, fmt.Errorf("%q is not a list type", listGVK.Kind)
   335  	}
   336  
   337  	t.lock.RLock()
   338  	defer t.lock.RUnlock()
   339  
   340  	objs, ok := t.objects[gvr]
   341  	if !ok {
   342  		return list, nil
   343  	}
   344  
   345  	matchingObjs, err := filterByNamespace(objs, ns)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  	if err := meta.SetList(list, matchingObjs); err != nil {
   350  		return nil, err
   351  	}
   352  	return list.DeepCopyObject(), nil
   353  }
   354  
   355  func (t *tracker) Watch(gvr schema.GroupVersionResource, ns string, opts ...metav1.ListOptions) (watch.Interface, error) {
   356  	_, err := assertOptionalSingleArgument(opts)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  
   361  	t.lock.Lock()
   362  	defer t.lock.Unlock()
   363  
   364  	fakewatcher := watch.NewRaceFreeFake()
   365  
   366  	if _, exists := t.watchers[gvr]; !exists {
   367  		t.watchers[gvr] = make(map[string][]*watch.RaceFreeFakeWatcher)
   368  	}
   369  	t.watchers[gvr][ns] = append(t.watchers[gvr][ns], fakewatcher)
   370  	return fakewatcher, nil
   371  }
   372  
   373  func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.GetOptions) (runtime.Object, error) {
   374  	_, err := assertOptionalSingleArgument(opts)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  	errNotFound := apierrors.NewNotFound(gvr.GroupResource(), name)
   379  
   380  	t.lock.RLock()
   381  	defer t.lock.RUnlock()
   382  
   383  	objs, ok := t.objects[gvr]
   384  	if !ok {
   385  		return nil, errNotFound
   386  	}
   387  
   388  	matchingObj, ok := objs[types.NamespacedName{Namespace: ns, Name: name}]
   389  	if !ok {
   390  		return nil, errNotFound
   391  	}
   392  
   393  	// Only one object should match in the tracker if it works
   394  	// correctly, as Add/Update methods enforce kind/namespace/name
   395  	// uniqueness.
   396  	obj := matchingObj.DeepCopyObject()
   397  	if status, ok := obj.(*metav1.Status); ok {
   398  		if status.Status != metav1.StatusSuccess {
   399  			return nil, &apierrors.StatusError{ErrStatus: *status}
   400  		}
   401  	}
   402  
   403  	return obj, nil
   404  }
   405  
   406  func (t *tracker) Add(obj runtime.Object) error {
   407  	if meta.IsListType(obj) {
   408  		return t.addList(obj, false)
   409  	}
   410  	objMeta, err := meta.Accessor(obj)
   411  	if err != nil {
   412  		return err
   413  	}
   414  	gvks, _, err := t.scheme.ObjectKinds(obj)
   415  	if err != nil {
   416  		return err
   417  	}
   418  
   419  	if partial, ok := obj.(*metav1.PartialObjectMetadata); ok && len(partial.TypeMeta.APIVersion) > 0 {
   420  		gvks = []schema.GroupVersionKind{partial.TypeMeta.GroupVersionKind()}
   421  	}
   422  
   423  	if len(gvks) == 0 {
   424  		return fmt.Errorf("no registered kinds for %v", obj)
   425  	}
   426  	for _, gvk := range gvks {
   427  		// NOTE: UnsafeGuessKindToResource is a heuristic and default match. The
   428  		// actual registration in apiserver can specify arbitrary route for a
   429  		// gvk. If a test uses such objects, it cannot preset the tracker with
   430  		// objects via Add(). Instead, it should trigger the Create() function
   431  		// of the tracker, where an arbitrary gvr can be specified.
   432  		gvr, _ := meta.UnsafeGuessKindToResource(gvk)
   433  		// Resource doesn't have the concept of "__internal" version, just set it to "".
   434  		if gvr.Version == runtime.APIVersionInternal {
   435  			gvr.Version = ""
   436  		}
   437  
   438  		err := t.add(gvr, obj, objMeta.GetNamespace(), false)
   439  		if err != nil {
   440  			return err
   441  		}
   442  	}
   443  	return nil
   444  }
   445  
   446  func (t *tracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.CreateOptions) error {
   447  	_, err := assertOptionalSingleArgument(opts)
   448  	if err != nil {
   449  		return err
   450  	}
   451  	return t.add(gvr, obj, ns, false)
   452  }
   453  
   454  func (t *tracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.UpdateOptions) error {
   455  	_, err := assertOptionalSingleArgument(opts)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	return t.add(gvr, obj, ns, true)
   460  }
   461  
   462  func (t *tracker) Patch(gvr schema.GroupVersionResource, patchedObject runtime.Object, ns string, opts ...metav1.PatchOptions) error {
   463  	_, err := assertOptionalSingleArgument(opts)
   464  	if err != nil {
   465  		return err
   466  	}
   467  	return t.add(gvr, patchedObject, ns, true)
   468  }
   469  
   470  func (t *tracker) Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, opts ...metav1.PatchOptions) error {
   471  	_, err := assertOptionalSingleArgument(opts)
   472  	if err != nil {
   473  		return err
   474  	}
   475  	applyConfigurationMeta, err := meta.Accessor(applyConfiguration)
   476  	if err != nil {
   477  		return err
   478  	}
   479  
   480  	obj, err := t.Get(gvr, ns, applyConfigurationMeta.GetName(), metav1.GetOptions{})
   481  	if err != nil {
   482  		return err
   483  	}
   484  
   485  	old, err := json.Marshal(obj)
   486  	if err != nil {
   487  		return err
   488  	}
   489  
   490  	// reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields
   491  	// in obj that are removed by patch are cleared
   492  	value := reflect.ValueOf(obj)
   493  	value.Elem().Set(reflect.New(value.Type().Elem()).Elem())
   494  
   495  	// For backward compatibility with behavior 1.30 and earlier, continue to handle apply
   496  	// via strategic merge patch (clients may use fake.NewClientset and ManagedFieldObjectTracker
   497  	// for full field manager support).
   498  	patch, err := json.Marshal(applyConfiguration)
   499  	if err != nil {
   500  		return err
   501  	}
   502  	mergedByte, err := strategicpatch.StrategicMergePatch(old, patch, obj)
   503  	if err != nil {
   504  		return err
   505  	}
   506  	if err = json.Unmarshal(mergedByte, obj); err != nil {
   507  		return err
   508  	}
   509  
   510  	return t.add(gvr, obj, ns, true)
   511  }
   512  
   513  func (t *tracker) getWatches(gvr schema.GroupVersionResource, ns string) []*watch.RaceFreeFakeWatcher {
   514  	watches := []*watch.RaceFreeFakeWatcher{}
   515  	if t.watchers[gvr] != nil {
   516  		if w := t.watchers[gvr][ns]; w != nil {
   517  			watches = append(watches, w...)
   518  		}
   519  		if ns != metav1.NamespaceAll {
   520  			if w := t.watchers[gvr][metav1.NamespaceAll]; w != nil {
   521  				watches = append(watches, w...)
   522  			}
   523  		}
   524  	}
   525  	return watches
   526  }
   527  
   528  func (t *tracker) add(gvr schema.GroupVersionResource, obj runtime.Object, ns string, replaceExisting bool) error {
   529  	t.lock.Lock()
   530  	defer t.lock.Unlock()
   531  
   532  	gr := gvr.GroupResource()
   533  
   534  	// To avoid the object from being accidentally modified by caller
   535  	// after it's been added to the tracker, we always store the deep
   536  	// copy.
   537  	obj = obj.DeepCopyObject()
   538  
   539  	newMeta, err := meta.Accessor(obj)
   540  	if err != nil {
   541  		return err
   542  	}
   543  
   544  	// Propagate namespace to the new object if hasn't already been set.
   545  	if len(newMeta.GetNamespace()) == 0 {
   546  		newMeta.SetNamespace(ns)
   547  	}
   548  
   549  	if ns != newMeta.GetNamespace() {
   550  		msg := fmt.Sprintf("request namespace does not match object namespace, request: %q object: %q", ns, newMeta.GetNamespace())
   551  		return apierrors.NewBadRequest(msg)
   552  	}
   553  
   554  	_, ok := t.objects[gvr]
   555  	if !ok {
   556  		t.objects[gvr] = make(map[types.NamespacedName]runtime.Object)
   557  	}
   558  
   559  	namespacedName := types.NamespacedName{Namespace: newMeta.GetNamespace(), Name: newMeta.GetName()}
   560  	if _, ok = t.objects[gvr][namespacedName]; ok {
   561  		if replaceExisting {
   562  			for _, w := range t.getWatches(gvr, ns) {
   563  				// To avoid the object from being accidentally modified by watcher
   564  				w.Modify(obj.DeepCopyObject())
   565  			}
   566  			t.objects[gvr][namespacedName] = obj
   567  			return nil
   568  		}
   569  		return apierrors.NewAlreadyExists(gr, newMeta.GetName())
   570  	}
   571  
   572  	if replaceExisting {
   573  		// Tried to update but no matching object was found.
   574  		return apierrors.NewNotFound(gr, newMeta.GetName())
   575  	}
   576  
   577  	t.objects[gvr][namespacedName] = obj
   578  
   579  	for _, w := range t.getWatches(gvr, ns) {
   580  		// To avoid the object from being accidentally modified by watcher
   581  		w.Add(obj.DeepCopyObject())
   582  	}
   583  
   584  	return nil
   585  }
   586  
   587  func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error {
   588  	list, err := meta.ExtractList(obj)
   589  	if err != nil {
   590  		return err
   591  	}
   592  	errs := runtime.DecodeList(list, t.decoder)
   593  	if len(errs) > 0 {
   594  		return errs[0]
   595  	}
   596  	for _, obj := range list {
   597  		if err := t.Add(obj); err != nil {
   598  			return err
   599  		}
   600  	}
   601  	return nil
   602  }
   603  
   604  func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string, opts ...metav1.DeleteOptions) error {
   605  	_, err := assertOptionalSingleArgument(opts)
   606  	if err != nil {
   607  		return err
   608  	}
   609  	t.lock.Lock()
   610  	defer t.lock.Unlock()
   611  
   612  	objs, ok := t.objects[gvr]
   613  	if !ok {
   614  		return apierrors.NewNotFound(gvr.GroupResource(), name)
   615  	}
   616  
   617  	namespacedName := types.NamespacedName{Namespace: ns, Name: name}
   618  	obj, ok := objs[namespacedName]
   619  	if !ok {
   620  		return apierrors.NewNotFound(gvr.GroupResource(), name)
   621  	}
   622  
   623  	delete(objs, namespacedName)
   624  	for _, w := range t.getWatches(gvr, ns) {
   625  		w.Delete(obj.DeepCopyObject())
   626  	}
   627  	return nil
   628  }
   629  
   630  type managedFieldObjectTracker struct {
   631  	ObjectTracker
   632  	scheme          ObjectScheme
   633  	objectConverter runtime.ObjectConvertor
   634  	mapper          meta.RESTMapper
   635  	typeConverter   managedfields.TypeConverter
   636  }
   637  
   638  var _ ObjectTracker = &managedFieldObjectTracker{}
   639  
   640  // NewFieldManagedObjectTracker returns an ObjectTracker that can be used to keep track
   641  // of objects and managed fields for the fake clientset. Mostly useful for unit tests.
   642  func NewFieldManagedObjectTracker(scheme *runtime.Scheme, decoder runtime.Decoder, typeConverter managedfields.TypeConverter) ObjectTracker {
   643  	return &managedFieldObjectTracker{
   644  		ObjectTracker:   NewObjectTracker(scheme, decoder),
   645  		scheme:          scheme,
   646  		objectConverter: scheme,
   647  		mapper:          testrestmapper.TestOnlyStaticRESTMapper(scheme),
   648  		typeConverter:   typeConverter,
   649  	}
   650  }
   651  
   652  func (t *managedFieldObjectTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, vopts ...metav1.CreateOptions) error {
   653  	opts, err := assertOptionalSingleArgument(vopts)
   654  	if err != nil {
   655  		return err
   656  	}
   657  	gvk, err := t.mapper.KindFor(gvr)
   658  	if err != nil {
   659  		return err
   660  	}
   661  	mgr, err := t.fieldManagerFor(gvk)
   662  	if err != nil {
   663  		return err
   664  	}
   665  
   666  	objType, err := meta.TypeAccessor(obj)
   667  	if err != nil {
   668  		return err
   669  	}
   670  	// Stamp GVK
   671  	apiVersion, kind := gvk.ToAPIVersionAndKind()
   672  	objType.SetAPIVersion(apiVersion)
   673  	objType.SetKind(kind)
   674  
   675  	objMeta, err := meta.Accessor(obj)
   676  	if err != nil {
   677  		return err
   678  	}
   679  	liveObject, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   680  	if apierrors.IsNotFound(err) {
   681  		liveObject, err = t.scheme.New(gvk)
   682  		if err != nil {
   683  			return err
   684  		}
   685  		liveObject.GetObjectKind().SetGroupVersionKind(gvk)
   686  	} else if err != nil {
   687  		return err
   688  	}
   689  	objWithManagedFields, err := mgr.Update(liveObject, obj, opts.FieldManager)
   690  	if err != nil {
   691  		return err
   692  	}
   693  	return t.ObjectTracker.Create(gvr, objWithManagedFields, ns, opts)
   694  }
   695  
   696  func (t *managedFieldObjectTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, vopts ...metav1.UpdateOptions) error {
   697  	opts, err := assertOptionalSingleArgument(vopts)
   698  	if err != nil {
   699  		return err
   700  	}
   701  	gvk, err := t.mapper.KindFor(gvr)
   702  	if err != nil {
   703  		return err
   704  	}
   705  	mgr, err := t.fieldManagerFor(gvk)
   706  	if err != nil {
   707  		return err
   708  	}
   709  
   710  	objMeta, err := meta.Accessor(obj)
   711  	if err != nil {
   712  		return err
   713  	}
   714  	oldObj, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   715  	if err != nil {
   716  		return err
   717  	}
   718  	objWithManagedFields, err := mgr.Update(oldObj, obj, opts.FieldManager)
   719  	if err != nil {
   720  		return err
   721  	}
   722  
   723  	return t.ObjectTracker.Update(gvr, objWithManagedFields, ns, opts)
   724  }
   725  
   726  func (t *managedFieldObjectTracker) Patch(gvr schema.GroupVersionResource, patchedObject runtime.Object, ns string, vopts ...metav1.PatchOptions) error {
   727  	opts, err := assertOptionalSingleArgument(vopts)
   728  	if err != nil {
   729  		return err
   730  	}
   731  	gvk, err := t.mapper.KindFor(gvr)
   732  	if err != nil {
   733  		return err
   734  	}
   735  	mgr, err := t.fieldManagerFor(gvk)
   736  	if err != nil {
   737  		return err
   738  	}
   739  
   740  	objMeta, err := meta.Accessor(patchedObject)
   741  	if err != nil {
   742  		return err
   743  	}
   744  	oldObj, err := t.ObjectTracker.Get(gvr, ns, objMeta.GetName(), metav1.GetOptions{})
   745  	if err != nil {
   746  		return err
   747  	}
   748  	objWithManagedFields, err := mgr.Update(oldObj, patchedObject, opts.FieldManager)
   749  	if err != nil {
   750  		return err
   751  	}
   752  	return t.ObjectTracker.Patch(gvr, objWithManagedFields, ns, vopts...)
   753  }
   754  
   755  func (t *managedFieldObjectTracker) Apply(gvr schema.GroupVersionResource, applyConfiguration runtime.Object, ns string, vopts ...metav1.PatchOptions) error {
   756  	opts, err := assertOptionalSingleArgument(vopts)
   757  	if err != nil {
   758  		return err
   759  	}
   760  	gvk, err := t.mapper.KindFor(gvr)
   761  	if err != nil {
   762  		return err
   763  	}
   764  	applyConfigurationMeta, err := meta.Accessor(applyConfiguration)
   765  	if err != nil {
   766  		return err
   767  	}
   768  
   769  	exists := true
   770  	liveObject, err := t.ObjectTracker.Get(gvr, ns, applyConfigurationMeta.GetName(), metav1.GetOptions{})
   771  	if apierrors.IsNotFound(err) {
   772  		exists = false
   773  		liveObject, err = t.scheme.New(gvk)
   774  		if err != nil {
   775  			return err
   776  		}
   777  		liveObject.GetObjectKind().SetGroupVersionKind(gvk)
   778  	} else if err != nil {
   779  		return err
   780  	}
   781  	mgr, err := t.fieldManagerFor(gvk)
   782  	if err != nil {
   783  		return err
   784  	}
   785  	force := false
   786  	if opts.Force != nil {
   787  		force = *opts.Force
   788  	}
   789  	objWithManagedFields, err := mgr.Apply(liveObject, applyConfiguration, opts.FieldManager, force)
   790  	if err != nil {
   791  		return err
   792  	}
   793  
   794  	if !exists {
   795  		return t.ObjectTracker.Create(gvr, objWithManagedFields, ns, metav1.CreateOptions{
   796  			DryRun:          opts.DryRun,
   797  			FieldManager:    opts.FieldManager,
   798  			FieldValidation: opts.FieldValidation,
   799  		})
   800  	} else {
   801  		return t.ObjectTracker.Update(gvr, objWithManagedFields, ns, metav1.UpdateOptions{
   802  			DryRun:          opts.DryRun,
   803  			FieldManager:    opts.FieldManager,
   804  			FieldValidation: opts.FieldValidation,
   805  		})
   806  	}
   807  }
   808  
   809  func (t *managedFieldObjectTracker) fieldManagerFor(gvk schema.GroupVersionKind) (*managedfields.FieldManager, error) {
   810  	return managedfields.NewDefaultFieldManager(
   811  		t.typeConverter,
   812  		t.objectConverter,
   813  		&objectDefaulter{},
   814  		t.scheme,
   815  		gvk,
   816  		gvk.GroupVersion(),
   817  		"",
   818  		nil)
   819  }
   820  
   821  // objectDefaulter implements runtime.Defaulter, but it actually
   822  // does nothing.
   823  type objectDefaulter struct{}
   824  
   825  func (d *objectDefaulter) Default(_ runtime.Object) {}
   826  
   827  // filterByNamespace returns all objects in the collection that
   828  // match provided namespace. Empty namespace matches
   829  // non-namespaced objects.
   830  func filterByNamespace(objs map[types.NamespacedName]runtime.Object, ns string) ([]runtime.Object, error) {
   831  	var res []runtime.Object
   832  
   833  	for _, obj := range objs {
   834  		acc, err := meta.Accessor(obj)
   835  		if err != nil {
   836  			return nil, err
   837  		}
   838  		if ns != "" && acc.GetNamespace() != ns {
   839  			continue
   840  		}
   841  		res = append(res, obj)
   842  	}
   843  
   844  	// Sort res to get deterministic order.
   845  	sort.Slice(res, func(i, j int) bool {
   846  		acc1, _ := meta.Accessor(res[i])
   847  		acc2, _ := meta.Accessor(res[j])
   848  		if acc1.GetNamespace() != acc2.GetNamespace() {
   849  			return acc1.GetNamespace() < acc2.GetNamespace()
   850  		}
   851  		return acc1.GetName() < acc2.GetName()
   852  	})
   853  	return res, nil
   854  }
   855  
   856  func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc {
   857  	return func(action Action) (bool, watch.Interface, error) {
   858  		return true, watchInterface, err
   859  	}
   860  }
   861  
   862  // SimpleReactor is a Reactor.  Each reaction function is attached to a given verb,resource tuple.  "*" in either field matches everything for that value.
   863  // For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
   864  type SimpleReactor struct {
   865  	Verb     string
   866  	Resource string
   867  
   868  	Reaction ReactionFunc
   869  }
   870  
   871  func (r *SimpleReactor) Handles(action Action) bool {
   872  	verbCovers := r.Verb == "*" || r.Verb == action.GetVerb()
   873  	if !verbCovers {
   874  		return false
   875  	}
   876  
   877  	return resourceCovers(r.Resource, action)
   878  }
   879  
   880  func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) {
   881  	return r.Reaction(action)
   882  }
   883  
   884  // SimpleWatchReactor is a WatchReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
   885  // For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
   886  type SimpleWatchReactor struct {
   887  	Resource string
   888  
   889  	Reaction WatchReactionFunc
   890  }
   891  
   892  func (r *SimpleWatchReactor) Handles(action Action) bool {
   893  	return resourceCovers(r.Resource, action)
   894  }
   895  
   896  func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) {
   897  	return r.Reaction(action)
   898  }
   899  
   900  // SimpleProxyReactor is a ProxyReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
   901  // For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions.
   902  type SimpleProxyReactor struct {
   903  	Resource string
   904  
   905  	Reaction ProxyReactionFunc
   906  }
   907  
   908  func (r *SimpleProxyReactor) Handles(action Action) bool {
   909  	return resourceCovers(r.Resource, action)
   910  }
   911  
   912  func (r *SimpleProxyReactor) React(action Action) (bool, restclient.ResponseWrapper, error) {
   913  	return r.Reaction(action)
   914  }
   915  
   916  func resourceCovers(resource string, action Action) bool {
   917  	if resource == "*" {
   918  		return true
   919  	}
   920  
   921  	if resource == action.GetResource().Resource {
   922  		return true
   923  	}
   924  
   925  	if index := strings.Index(resource, "/"); index != -1 &&
   926  		resource[:index] == action.GetResource().Resource &&
   927  		resource[index+1:] == action.GetSubresource() {
   928  		return true
   929  	}
   930  
   931  	return false
   932  }
   933  
   934  // assertOptionalSingleArgument returns an error if there is more than one variadic argument.
   935  // Otherwise, it returns the first variadic argument, or zero value if there are no arguments.
   936  func assertOptionalSingleArgument[T any](arguments []T) (T, error) {
   937  	var a T
   938  	switch len(arguments) {
   939  	case 0:
   940  		return a, nil
   941  	case 1:
   942  		return arguments[0], nil
   943  	default:
   944  		return a, fmt.Errorf("expected only one option argument but got %d", len(arguments))
   945  	}
   946  }
   947  
   948  type TypeResolver interface {
   949  	Type(openAPIName string) typed.ParseableType
   950  }
   951  
   952  type TypeConverter struct {
   953  	Scheme       *runtime.Scheme
   954  	TypeResolver TypeResolver
   955  }
   956  
   957  func (tc TypeConverter) ObjectToTyped(obj runtime.Object, opts ...typed.ValidationOptions) (*typed.TypedValue, error) {
   958  	gvk := obj.GetObjectKind().GroupVersionKind()
   959  	name, err := tc.openAPIName(gvk)
   960  	if err != nil {
   961  		return nil, err
   962  	}
   963  	t := tc.TypeResolver.Type(name)
   964  	switch o := obj.(type) {
   965  	case *unstructured.Unstructured:
   966  		return t.FromUnstructured(o.UnstructuredContent(), opts...)
   967  	default:
   968  		return t.FromStructured(obj, opts...)
   969  	}
   970  }
   971  
   972  func (tc TypeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) {
   973  	vu := value.AsValue().Unstructured()
   974  	switch o := vu.(type) {
   975  	case map[string]interface{}:
   976  		return &unstructured.Unstructured{Object: o}, nil
   977  	default:
   978  		return nil, fmt.Errorf("failed to convert value to unstructured for type %T", vu)
   979  	}
   980  }
   981  
   982  func (tc TypeConverter) openAPIName(kind schema.GroupVersionKind) (string, error) {
   983  	example, err := tc.Scheme.New(kind)
   984  	if err != nil {
   985  		return "", err
   986  	}
   987  	rtype := reflect.TypeOf(example).Elem()
   988  	name := friendlyName(rtype.PkgPath() + "." + rtype.Name())
   989  	return name, nil
   990  }
   991  
   992  // This is a copy of openapi.friendlyName.
   993  // TODO: consider introducing a shared version of this function in apimachinery.
   994  func friendlyName(name string) string {
   995  	nameParts := strings.Split(name, "/")
   996  	// Reverse first part. e.g., io.k8s... instead of k8s.io...
   997  	if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
   998  		parts := strings.Split(nameParts[0], ".")
   999  		for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
  1000  			parts[i], parts[j] = parts[j], parts[i]
  1001  		}
  1002  		nameParts[0] = strings.Join(parts, ".")
  1003  	}
  1004  	return strings.Join(nameParts, ".")
  1005  }