diff options
Diffstat (limited to 'vendor/k8s.io/client-go/testing/fixture.go')
-rw-r--r-- | vendor/k8s.io/client-go/testing/fixture.go | 547 |
1 files changed, 0 insertions, 547 deletions
diff --git a/vendor/k8s.io/client-go/testing/fixture.go b/vendor/k8s.io/client-go/testing/fixture.go deleted file mode 100644 index 90f16f560..000000000 --- a/vendor/k8s.io/client-go/testing/fixture.go +++ /dev/null @@ -1,547 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package testing - -import ( - "fmt" - "sync" - - "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/apimachinery/pkg/util/strategicpatch" - "k8s.io/apimachinery/pkg/watch" - restclient "k8s.io/client-go/rest" -) - -// ObjectTracker keeps track of objects. It is intended to be used to -// fake calls to a server by returning objects based on their kind, -// namespace and name. -type ObjectTracker interface { - // Add adds an object to the tracker. If object being added - // is a list, its items are added separately. - Add(obj runtime.Object) error - - // Get retrieves the object by its kind, namespace and name. - Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error) - - // Create adds an object to the tracker in the specified namespace. - Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error - - // Update updates an existing object in the tracker in the specified namespace. - Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error - - // List retrieves all objects of a given kind in the given - // namespace. Only non-List kinds are accepted. - List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error) - - // Delete deletes an existing object from the tracker. If object - // didn't exist in the tracker prior to deletion, Delete returns - // no error. - Delete(gvr schema.GroupVersionResource, ns, name string) error - - // Watch watches objects from the tracker. Watch returns a channel - // which will push added / modified / deleted object. - Watch(gvr schema.GroupVersionResource, ns string) (watch.Interface, error) -} - -// ObjectScheme abstracts the implementation of common operations on objects. -type ObjectScheme interface { - runtime.ObjectCreater - runtime.ObjectTyper -} - -// ObjectReaction returns a ReactionFunc that applies core.Action to -// the given tracker. -func ObjectReaction(tracker ObjectTracker) ReactionFunc { - return func(action Action) (bool, runtime.Object, error) { - ns := action.GetNamespace() - gvr := action.GetResource() - // Here and below we need to switch on implementation types, - // not on interfaces, as some interfaces are identical - // (e.g. UpdateAction and CreateAction), so if we use them, - // updates and creates end up matching the same case branch. - switch action := action.(type) { - - case ListActionImpl: - obj, err := tracker.List(gvr, action.GetKind(), ns) - return true, obj, err - - case GetActionImpl: - obj, err := tracker.Get(gvr, ns, action.GetName()) - return true, obj, err - - case CreateActionImpl: - objMeta, err := meta.Accessor(action.GetObject()) - if err != nil { - return true, nil, err - } - if action.GetSubresource() == "" { - err = tracker.Create(gvr, action.GetObject(), ns) - } else { - // TODO: Currently we're handling subresource creation as an update - // on the enclosing resource. This works for some subresources but - // might not be generic enough. - err = tracker.Update(gvr, action.GetObject(), ns) - } - if err != nil { - return true, nil, err - } - obj, err := tracker.Get(gvr, ns, objMeta.GetName()) - return true, obj, err - - case UpdateActionImpl: - objMeta, err := meta.Accessor(action.GetObject()) - if err != nil { - return true, nil, err - } - err = tracker.Update(gvr, action.GetObject(), ns) - if err != nil { - return true, nil, err - } - obj, err := tracker.Get(gvr, ns, objMeta.GetName()) - return true, obj, err - - case DeleteActionImpl: - err := tracker.Delete(gvr, ns, action.GetName()) - if err != nil { - return true, nil, err - } - return true, nil, nil - - case PatchActionImpl: - obj, err := tracker.Get(gvr, ns, action.GetName()) - if err != nil { - // object is not registered - return false, nil, err - } - - old, err := json.Marshal(obj) - if err != nil { - return true, nil, err - } - // Only supports strategic merge patch and JSONPatch as coded. - switch action.GetPatchType() { - case types.JSONPatchType: - patch, err := jsonpatch.DecodePatch(action.GetPatch()) - if err != nil { - return true, nil, err - } - modified, err := patch.Apply(old) - if err != nil { - return true, nil, err - } - if err = json.Unmarshal(modified, obj); err != nil { - return true, nil, err - } - case types.StrategicMergePatchType: - mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj) - if err != nil { - return true, nil, err - } - if err = json.Unmarshal(mergedByte, obj); err != nil { - return true, nil, err - } - default: - return true, nil, fmt.Errorf("PatchType is not supported") - } - - if err = tracker.Update(gvr, obj, ns); err != nil { - return true, nil, err - } - - return true, obj, nil - - default: - return false, nil, fmt.Errorf("no reaction implemented for %s", action) - } - } -} - -type tracker struct { - scheme ObjectScheme - decoder runtime.Decoder - lock sync.RWMutex - objects map[schema.GroupVersionResource][]runtime.Object - // The value type of watchers is a map of which the key is either a namespace or - // all/non namespace aka "" and its value is list of fake watchers. - // Manipulations on resources will broadcast the notification events into the - // watchers' channel. Note that too many unhandled events (currently 100, - // see apimachinery/pkg/watch.DefaultChanSize) will cause a panic. - watchers map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher -} - -var _ ObjectTracker = &tracker{} - -// NewObjectTracker returns an ObjectTracker that can be used to keep track -// of objects for the fake clientset. Mostly useful for unit tests. -func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker { - return &tracker{ - scheme: scheme, - decoder: decoder, - objects: make(map[schema.GroupVersionResource][]runtime.Object), - watchers: make(map[schema.GroupVersionResource]map[string][]*watch.RaceFreeFakeWatcher), - } -} - -func (t *tracker) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error) { - // Heuristic for list kind: original kind + List suffix. Might - // not always be true but this tracker has a pretty limited - // understanding of the actual API model. - listGVK := gvk - listGVK.Kind = listGVK.Kind + "List" - // GVK does have the concept of "internal version". The scheme recognizes - // the runtime.APIVersionInternal, but not the empty string. - if listGVK.Version == "" { - listGVK.Version = runtime.APIVersionInternal - } - - list, err := t.scheme.New(listGVK) - if err != nil { - return nil, err - } - - if !meta.IsListType(list) { - return nil, fmt.Errorf("%q is not a list type", listGVK.Kind) - } - - t.lock.RLock() - defer t.lock.RUnlock() - - objs, ok := t.objects[gvr] - if !ok { - return list, nil - } - - matchingObjs, err := filterByNamespaceAndName(objs, ns, "") - if err != nil { - return nil, err - } - if err := meta.SetList(list, matchingObjs); err != nil { - return nil, err - } - return list.DeepCopyObject(), nil -} - -func (t *tracker) Watch(gvr schema.GroupVersionResource, ns string) (watch.Interface, error) { - t.lock.Lock() - defer t.lock.Unlock() - - fakewatcher := watch.NewRaceFreeFake() - - if _, exists := t.watchers[gvr]; !exists { - t.watchers[gvr] = make(map[string][]*watch.RaceFreeFakeWatcher) - } - t.watchers[gvr][ns] = append(t.watchers[gvr][ns], fakewatcher) - return fakewatcher, nil -} - -func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error) { - errNotFound := errors.NewNotFound(gvr.GroupResource(), name) - - t.lock.RLock() - defer t.lock.RUnlock() - - objs, ok := t.objects[gvr] - if !ok { - return nil, errNotFound - } - - matchingObjs, err := filterByNamespaceAndName(objs, ns, name) - if err != nil { - return nil, err - } - if len(matchingObjs) == 0 { - return nil, errNotFound - } - if len(matchingObjs) > 1 { - return nil, fmt.Errorf("more than one object matched gvr %s, ns: %q name: %q", gvr, ns, name) - } - - // Only one object should match in the tracker if it works - // correctly, as Add/Update methods enforce kind/namespace/name - // uniqueness. - obj := matchingObjs[0].DeepCopyObject() - if status, ok := obj.(*metav1.Status); ok { - if status.Status != metav1.StatusSuccess { - return nil, &errors.StatusError{ErrStatus: *status} - } - } - - return obj, nil -} - -func (t *tracker) Add(obj runtime.Object) error { - if meta.IsListType(obj) { - return t.addList(obj, false) - } - objMeta, err := meta.Accessor(obj) - if err != nil { - return err - } - gvks, _, err := t.scheme.ObjectKinds(obj) - if err != nil { - return err - } - if len(gvks) == 0 { - return fmt.Errorf("no registered kinds for %v", obj) - } - for _, gvk := range gvks { - // NOTE: UnsafeGuessKindToResource is a heuristic and default match. The - // actual registration in apiserver can specify arbitrary route for a - // gvk. If a test uses such objects, it cannot preset the tracker with - // objects via Add(). Instead, it should trigger the Create() function - // of the tracker, where an arbitrary gvr can be specified. - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - // Resource doesn't have the concept of "__internal" version, just set it to "". - if gvr.Version == runtime.APIVersionInternal { - gvr.Version = "" - } - - err := t.add(gvr, obj, objMeta.GetNamespace(), false) - if err != nil { - return err - } - } - return nil -} - -func (t *tracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - return t.add(gvr, obj, ns, false) -} - -func (t *tracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error { - return t.add(gvr, obj, ns, true) -} - -func (t *tracker) getWatches(gvr schema.GroupVersionResource, ns string) []*watch.RaceFreeFakeWatcher { - watches := []*watch.RaceFreeFakeWatcher{} - if t.watchers[gvr] != nil { - if w := t.watchers[gvr][ns]; w != nil { - watches = append(watches, w...) - } - if w := t.watchers[gvr][""]; w != nil { - watches = append(watches, w...) - } - } - return watches -} - -func (t *tracker) add(gvr schema.GroupVersionResource, obj runtime.Object, ns string, replaceExisting bool) error { - t.lock.Lock() - defer t.lock.Unlock() - - gr := gvr.GroupResource() - - // To avoid the object from being accidentally modified by caller - // after it's been added to the tracker, we always store the deep - // copy. - obj = obj.DeepCopyObject() - - newMeta, err := meta.Accessor(obj) - if err != nil { - return err - } - - // Propagate namespace to the new object if hasn't already been set. - if len(newMeta.GetNamespace()) == 0 { - newMeta.SetNamespace(ns) - } - - if ns != newMeta.GetNamespace() { - msg := fmt.Sprintf("request namespace does not match object namespace, request: %q object: %q", ns, newMeta.GetNamespace()) - return errors.NewBadRequest(msg) - } - - for i, existingObj := range t.objects[gvr] { - oldMeta, err := meta.Accessor(existingObj) - if err != nil { - return err - } - if oldMeta.GetNamespace() == newMeta.GetNamespace() && oldMeta.GetName() == newMeta.GetName() { - if replaceExisting { - for _, w := range t.getWatches(gvr, ns) { - w.Modify(obj) - } - t.objects[gvr][i] = obj - return nil - } - return errors.NewAlreadyExists(gr, newMeta.GetName()) - } - } - - if replaceExisting { - // Tried to update but no matching object was found. - return errors.NewNotFound(gr, newMeta.GetName()) - } - - t.objects[gvr] = append(t.objects[gvr], obj) - - for _, w := range t.getWatches(gvr, ns) { - w.Add(obj) - } - - return nil -} - -func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error { - list, err := meta.ExtractList(obj) - if err != nil { - return err - } - errs := runtime.DecodeList(list, t.decoder) - if len(errs) > 0 { - return errs[0] - } - for _, obj := range list { - if err := t.Add(obj); err != nil { - return err - } - } - return nil -} - -func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string) error { - t.lock.Lock() - defer t.lock.Unlock() - - found := false - - for i, existingObj := range t.objects[gvr] { - objMeta, err := meta.Accessor(existingObj) - if err != nil { - return err - } - if objMeta.GetNamespace() == ns && objMeta.GetName() == name { - obj := t.objects[gvr][i] - t.objects[gvr] = append(t.objects[gvr][:i], t.objects[gvr][i+1:]...) - for _, w := range t.getWatches(gvr, ns) { - w.Delete(obj) - } - found = true - break - } - } - - if found { - return nil - } - - return errors.NewNotFound(gvr.GroupResource(), name) -} - -// filterByNamespaceAndName returns all objects in the collection that -// match provided namespace and name. Empty namespace matches -// non-namespaced objects. -func filterByNamespaceAndName(objs []runtime.Object, ns, name string) ([]runtime.Object, error) { - var res []runtime.Object - - for _, obj := range objs { - acc, err := meta.Accessor(obj) - if err != nil { - return nil, err - } - if ns != "" && acc.GetNamespace() != ns { - continue - } - if name != "" && acc.GetName() != name { - continue - } - res = append(res, obj) - } - - return res, nil -} - -func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc { - return func(action Action) (bool, watch.Interface, error) { - return true, watchInterface, err - } -} - -// SimpleReactor is a Reactor. Each reaction function is attached to a given verb,resource tuple. "*" in either field matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions -type SimpleReactor struct { - Verb string - Resource string - - Reaction ReactionFunc -} - -func (r *SimpleReactor) Handles(action Action) bool { - verbCovers := r.Verb == "*" || r.Verb == action.GetVerb() - if !verbCovers { - return false - } - resourceCovers := r.Resource == "*" || r.Resource == action.GetResource().Resource - if !resourceCovers { - return false - } - - return true -} - -func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) { - return r.Reaction(action) -} - -// SimpleWatchReactor is a WatchReactor. Each reaction function is attached to a given resource. "*" matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions -type SimpleWatchReactor struct { - Resource string - - Reaction WatchReactionFunc -} - -func (r *SimpleWatchReactor) Handles(action Action) bool { - resourceCovers := r.Resource == "*" || r.Resource == action.GetResource().Resource - if !resourceCovers { - return false - } - - return true -} - -func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) { - return r.Reaction(action) -} - -// SimpleProxyReactor is a ProxyReactor. Each reaction function is attached to a given resource. "*" matches everything for that value. -// For instance, *,pods matches all verbs on pods. This allows for easier composition of reaction functions. -type SimpleProxyReactor struct { - Resource string - - Reaction ProxyReactionFunc -} - -func (r *SimpleProxyReactor) Handles(action Action) bool { - resourceCovers := r.Resource == "*" || r.Resource == action.GetResource().Resource - if !resourceCovers { - return false - } - - return true -} - -func (r *SimpleProxyReactor) React(action Action) (bool, restclient.ResponseWrapper, error) { - return r.Reaction(action) -} |