remove registry from testing/fixture.go; update client-gen to not use

registry in the generated clients
This commit is contained in:
Chao Xu 2017-04-29 15:43:28 -07:00
parent ca520e34a3
commit bbb94e42c1
12 changed files with 165 additions and 204 deletions

View File

@ -128,7 +128,6 @@ func PackageForClientset(customArgs clientgenargs.Args, fakeClientsetPackage str
Groups: customArgs.Groups, Groups: customArgs.Groups,
ImportTracker: generator.NewImportTracker(), ImportTracker: generator.NewImportTracker(),
PrivateScheme: true, PrivateScheme: true,
CreateRegistry: true, // needed to know about root resources and for RESTMapper
}, },
} }
return generators return generators

View File

@ -108,7 +108,7 @@ var common = `
// without applying any validations and/or defaults. It shouldn't be considered a replacement // without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests. // for a real clientset and is mostly useful in simple unit tests.
func NewSimpleClientset(objects ...runtime.Object) *Clientset { func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(registry, scheme, codecs.UniversalDecoder()) o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects { for _, obj := range objects {
if err := o.Add(obj); err != nil { if err := o.Add(obj); err != nil {
panic(err) panic(err)
@ -116,7 +116,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
} }
fakePtr := testing.Fake{} fakePtr := testing.Fake{}
fakePtr.AddReactor("*", "*", testing.ObjectReaction(o, registry.RESTMapper())) fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil)) fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil))

View File

@ -120,6 +120,7 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}), "Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}),
"GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}), "GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}),
"GroupVersionKind": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
@ -156,6 +157,7 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
if !noMethods { if !noMethods {
sw.Do(resource, m) sw.Do(resource, m)
sw.Do(kind, m)
sw.Do(createTemplate, m) sw.Do(createTemplate, m)
sw.Do(updateTemplate, m) sw.Do(updateTemplate, m)
// Generate the UpdateStatus method if the type has a status // Generate the UpdateStatus method if the type has a status
@ -198,11 +200,15 @@ var resource = `
var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|allLowercasePlural$"} var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|allLowercasePlural$"}
` `
var kind = `
var $.type|allLowercasePlural$Kind = $.GroupVersionKind|raw${Group: "$.groupName$", Version: "$.version$", Kind: "$.type|public$"}
`
var listTemplate = ` var listTemplate = `
func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, c.ns, opts), &$.type|raw$List{}) $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, opts), &$.type|raw$List{})$end$ $else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
@ -213,8 +219,8 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type
var listUsingOptionsTemplate = ` var listUsingOptionsTemplate = `
func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, c.ns, opts), &$.type|raw$List{}) $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, opts), &$.type|raw$List{})$end$ $else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$
if obj == nil { if obj == nil {
return nil, err return nil, err
} }

View File

@ -67,9 +67,9 @@ func (c *FakeEvents) PatchWithEventNamespace(event *v1.Event, data []byte) (*v1.
// Search returns a list of events matching the specified object. // Search returns a list of events matching the specified object.
func (c *FakeEvents) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*v1.EventList, error) { func (c *FakeEvents) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*v1.EventList, error) {
action := core.NewRootListAction(eventsResource, metav1.ListOptions{}) action := core.NewRootListAction(eventsResource, eventsKind, metav1.ListOptions{})
if c.ns != "" { if c.ns != "" {
action = core.NewListAction(eventsResource, c.ns, metav1.ListOptions{}) action = core.NewListAction(eventsResource, eventsKind, c.ns, metav1.ListOptions{})
} }
obj, err := c.Fake.Invokes(action, &v1.EventList{}) obj, err := c.Fake.Invokes(action, &v1.EventList{})
if obj == nil { if obj == nil {

View File

@ -67,9 +67,9 @@ func (c *FakeEvents) PatchWithEventNamespace(event *api.Event, data []byte) (*ap
// Search returns a list of events matching the specified object. // Search returns a list of events matching the specified object.
func (c *FakeEvents) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*api.EventList, error) { func (c *FakeEvents) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*api.EventList, error) {
action := core.NewRootListAction(eventsResource, metav1.ListOptions{}) action := core.NewRootListAction(eventsResource, eventsKind, metav1.ListOptions{})
if c.ns != "" { if c.ns != "" {
action = core.NewListAction(eventsResource, c.ns, metav1.ListOptions{}) action = core.NewListAction(eventsResource, eventsKind, c.ns, metav1.ListOptions{})
} }
obj, err := c.Fake.Invokes(action, &api.EventList{}) obj, err := c.Fake.Invokes(action, &api.EventList{})
if obj == nil { if obj == nil {

View File

@ -19,6 +19,7 @@ package util
import ( import (
"reflect" "reflect"
"testing" "testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -31,7 +32,6 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"time"
) )
type fakeClientAccessFactory struct { type fakeClientAccessFactory struct {
@ -52,6 +52,7 @@ func newFakeClientAccessFactory(objs []runtime.Object) *fakeClientAccessFactory
var ( var (
podsResource = schema.GroupVersionResource{Resource: "pods"} podsResource = schema.GroupVersionResource{Resource: "pods"}
podsKind = schema.GroupVersionKind{Kind: "Pod"}
) )
func TestLogsForObject(t *testing.T) { func TestLogsForObject(t *testing.T) {
@ -82,7 +83,7 @@ func TestLogsForObject(t *testing.T) {
}, },
pods: []runtime.Object{testPod()}, pods: []runtime.Object{testPod()},
actions: []testclient.Action{ actions: []testclient.Action{
testclient.NewListAction(podsResource, "test", metav1.ListOptions{LabelSelector: "foo=bar"}), testclient.NewListAction(podsResource, podsKind, "test", metav1.ListOptions{LabelSelector: "foo=bar"}),
getLogsAction("test", nil), getLogsAction("test", nil),
}, },
}, },
@ -96,7 +97,7 @@ func TestLogsForObject(t *testing.T) {
}, },
pods: []runtime.Object{testPod()}, pods: []runtime.Object{testPod()},
actions: []testclient.Action{ actions: []testclient.Action{
testclient.NewListAction(podsResource, "test", metav1.ListOptions{LabelSelector: "foo=bar"}), testclient.NewListAction(podsResource, podsKind, "test", metav1.ListOptions{LabelSelector: "foo=bar"}),
getLogsAction("test", nil), getLogsAction("test", nil),
}, },
}, },
@ -110,7 +111,7 @@ func TestLogsForObject(t *testing.T) {
}, },
pods: []runtime.Object{testPod()}, pods: []runtime.Object{testPod()},
actions: []testclient.Action{ actions: []testclient.Action{
testclient.NewListAction(podsResource, "test", metav1.ListOptions{LabelSelector: "foo=bar"}), testclient.NewListAction(podsResource, podsKind, "test", metav1.ListOptions{LabelSelector: "foo=bar"}),
getLogsAction("test", nil), getLogsAction("test", nil),
}, },
}, },
@ -124,7 +125,7 @@ func TestLogsForObject(t *testing.T) {
}, },
pods: []runtime.Object{testPod()}, pods: []runtime.Object{testPod()},
actions: []testclient.Action{ actions: []testclient.Action{
testclient.NewListAction(podsResource, "test", metav1.ListOptions{LabelSelector: "foo=bar"}), testclient.NewListAction(podsResource, podsKind, "test", metav1.ListOptions{LabelSelector: "foo=bar"}),
getLogsAction("test", nil), getLogsAction("test", nil),
}, },
}, },
@ -138,7 +139,7 @@ func TestLogsForObject(t *testing.T) {
}, },
pods: []runtime.Object{testPod()}, pods: []runtime.Object{testPod()},
actions: []testclient.Action{ actions: []testclient.Action{
testclient.NewListAction(podsResource, "test", metav1.ListOptions{LabelSelector: "foo=bar"}), testclient.NewListAction(podsResource, podsKind, "test", metav1.ListOptions{LabelSelector: "foo=bar"}),
getLogsAction("test", nil), getLogsAction("test", nil),
}, },
}, },

View File

@ -47,20 +47,22 @@ func NewGetAction(resource schema.GroupVersionResource, namespace, name string)
return action return action
} }
func NewRootListAction(resource schema.GroupVersionResource, opts interface{}) ListActionImpl { func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl {
action := ListActionImpl{} action := ListActionImpl{}
action.Verb = "list" action.Verb = "list"
action.Resource = resource action.Resource = resource
action.Kind = kind
labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
return action return action
} }
func NewListAction(resource schema.GroupVersionResource, namespace string, opts interface{}) ListActionImpl { func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl {
action := ListActionImpl{} action := ListActionImpl{}
action.Verb = "list" action.Verb = "list"
action.Resource = resource action.Resource = resource
action.Kind = kind
action.Namespace = namespace action.Namespace = namespace
labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) labelSelector, fieldSelector, _ := ExtractFromListOptions(opts)
action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector}
@ -375,9 +377,14 @@ func (a GetActionImpl) GetName() string {
type ListActionImpl struct { type ListActionImpl struct {
ActionImpl ActionImpl
Kind schema.GroupVersionKind
ListRestrictions ListRestrictions ListRestrictions ListRestrictions
} }
func (a ListActionImpl) GetKind() schema.GroupVersionKind {
return a.Kind
}
func (a ListActionImpl) GetListRestrictions() ListRestrictions { func (a ListActionImpl) GetListRestrictions() ListRestrictions {
return a.ListRestrictions return a.ListRestrictions
} }

View File

@ -22,7 +22,6 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery/registered"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -39,22 +38,22 @@ type ObjectTracker interface {
Add(obj runtime.Object) error Add(obj runtime.Object) error
// Get retrieves the object by its kind, namespace and name. // Get retrieves the object by its kind, namespace and name.
Get(gvk schema.GroupVersionKind, ns, name string) (runtime.Object, error) Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error)
// Create adds an object to the tracker in the specified namespace. // Create adds an object to the tracker in the specified namespace.
Create(obj runtime.Object, ns string) error Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error
// Update updates an existing object in the tracker in the specified namespace. // Update updates an existing object in the tracker in the specified namespace.
Update(obj runtime.Object, ns string) error Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error
// List retrieves all objects of a given kind in the given // List retrieves all objects of a given kind in the given
// namespace. Only non-List kinds are accepted. // namespace. Only non-List kinds are accepted.
List(gvk schema.GroupVersionKind, ns string) (runtime.Object, error) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error)
// Delete deletes an existing object from the tracker. If object // Delete deletes an existing object from the tracker. If object
// didn't exist in the tracker prior to deletion, Delete returns // didn't exist in the tracker prior to deletion, Delete returns
// no error. // no error.
Delete(gvk schema.GroupVersionKind, ns, name string) error Delete(gvr schema.GroupVersionResource, ns, name string) error
} }
// ObjectScheme abstracts the implementation of common operations on objects. // ObjectScheme abstracts the implementation of common operations on objects.
@ -66,25 +65,11 @@ type ObjectScheme interface {
// ObjectReaction returns a ReactionFunc that applies core.Action to // ObjectReaction returns a ReactionFunc that applies core.Action to
// the given tracker. // the given tracker.
func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc { func ObjectReaction(tracker ObjectTracker) ReactionFunc {
return func(action Action) (bool, runtime.Object, error) { return func(action Action) (bool, runtime.Object, error) {
ns := action.GetNamespace() ns := action.GetNamespace()
gvr := action.GetResource() gvr := action.GetResource()
gvk, err := mapper.KindFor(gvr)
if err != nil {
return false, nil, fmt.Errorf("error getting kind for resource %q: %s", gvr, err)
}
// This is a temporary fix. Because there is no internal resource, so
// the caller has no way to express that it expects to get an internal
// kind back. A more proper fix will be directly specify the Kind when
// build the action.
gvk.Version = gvr.Version
if len(gvk.Version) == 0 {
gvk.Version = runtime.APIVersionInternal
}
// Here and below we need to switch on implementation types, // Here and below we need to switch on implementation types,
// not on interfaces, as some interfaces are identical // not on interfaces, as some interfaces are identical
// (e.g. UpdateAction and CreateAction), so if we use them, // (e.g. UpdateAction and CreateAction), so if we use them,
@ -92,11 +77,11 @@ func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc
switch action := action.(type) { switch action := action.(type) {
case ListActionImpl: case ListActionImpl:
obj, err := tracker.List(gvk, ns) obj, err := tracker.List(gvr, action.GetKind(), ns)
return true, obj, err return true, obj, err
case GetActionImpl: case GetActionImpl:
obj, err := tracker.Get(gvk, ns, action.GetName()) obj, err := tracker.Get(gvr, ns, action.GetName())
return true, obj, err return true, obj, err
case CreateActionImpl: case CreateActionImpl:
@ -105,17 +90,17 @@ func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc
return true, nil, err return true, nil, err
} }
if action.GetSubresource() == "" { if action.GetSubresource() == "" {
err = tracker.Create(action.GetObject(), ns) err = tracker.Create(gvr, action.GetObject(), ns)
} else { } else {
// TODO: Currently we're handling subresource creation as an update // TODO: Currently we're handling subresource creation as an update
// on the enclosing resource. This works for some subresources but // on the enclosing resource. This works for some subresources but
// might not be generic enough. // might not be generic enough.
err = tracker.Update(action.GetObject(), ns) err = tracker.Update(gvr, action.GetObject(), ns)
} }
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
obj, err := tracker.Get(gvk, ns, objMeta.GetName()) obj, err := tracker.Get(gvr, ns, objMeta.GetName())
return true, obj, err return true, obj, err
case UpdateActionImpl: case UpdateActionImpl:
@ -123,15 +108,15 @@ func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
err = tracker.Update(action.GetObject(), ns) err = tracker.Update(gvr, action.GetObject(), ns)
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
obj, err := tracker.Get(gvk, ns, objMeta.GetName()) obj, err := tracker.Get(gvr, ns, objMeta.GetName())
return true, obj, err return true, obj, err
case DeleteActionImpl: case DeleteActionImpl:
err := tracker.Delete(gvk, ns, action.GetName()) err := tracker.Delete(gvr, ns, action.GetName())
if err != nil { if err != nil {
return true, nil, err return true, nil, err
} }
@ -144,32 +129,35 @@ func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc
} }
type tracker struct { type tracker struct {
registry *registered.APIRegistrationManager
scheme ObjectScheme scheme ObjectScheme
decoder runtime.Decoder decoder runtime.Decoder
lock sync.RWMutex lock sync.RWMutex
objects map[schema.GroupVersionKind][]runtime.Object objects map[schema.GroupVersionResource][]runtime.Object
} }
var _ ObjectTracker = &tracker{} var _ ObjectTracker = &tracker{}
// NewObjectTracker returns an ObjectTracker that can be used to keep track // NewObjectTracker returns an ObjectTracker that can be used to keep track
// of objects for the fake clientset. Mostly useful for unit tests. // of objects for the fake clientset. Mostly useful for unit tests.
func NewObjectTracker(registry *registered.APIRegistrationManager, scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker { func NewObjectTracker(scheme ObjectScheme, decoder runtime.Decoder) ObjectTracker {
return &tracker{ return &tracker{
registry: registry,
scheme: scheme, scheme: scheme,
decoder: decoder, decoder: decoder,
objects: make(map[schema.GroupVersionKind][]runtime.Object), objects: make(map[schema.GroupVersionResource][]runtime.Object),
} }
} }
func (t *tracker) List(gvk schema.GroupVersionKind, ns string) (runtime.Object, error) { func (t *tracker) List(gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, ns string) (runtime.Object, error) {
// Heuristic for list kind: original kind + List suffix. Might // Heuristic for list kind: original kind + List suffix. Might
// not always be true but this tracker has a pretty limited // not always be true but this tracker has a pretty limited
// understanding of the actual API model. // understanding of the actual API model.
listGVK := gvk listGVK := gvk
listGVK.Kind = listGVK.Kind + "List" 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) list, err := t.scheme.New(listGVK)
if err != nil { if err != nil {
@ -183,7 +171,7 @@ func (t *tracker) List(gvk schema.GroupVersionKind, ns string) (runtime.Object,
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
objs, ok := t.objects[gvk] objs, ok := t.objects[gvr]
if !ok { if !ok {
return list, nil return list, nil
} }
@ -201,17 +189,13 @@ func (t *tracker) List(gvk schema.GroupVersionKind, ns string) (runtime.Object,
return list, nil return list, nil
} }
func (t *tracker) Get(gvk schema.GroupVersionKind, ns, name string) (runtime.Object, error) { func (t *tracker) Get(gvr schema.GroupVersionResource, ns, name string) (runtime.Object, error) {
if err := checkNamespace(t.registry, gvk, ns); err != nil { errNotFound := errors.NewNotFound(gvr.GroupResource(), name)
return nil, err
}
errNotFound := errors.NewNotFound(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, name)
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
objs, ok := t.objects[gvk] objs, ok := t.objects[gvr]
if !ok { if !ok {
return nil, errNotFound return nil, errNotFound
} }
@ -224,7 +208,7 @@ func (t *tracker) Get(gvk schema.GroupVersionKind, ns, name string) (runtime.Obj
return nil, errNotFound return nil, errNotFound
} }
if len(matchingObjs) > 1 { if len(matchingObjs) > 1 {
return nil, fmt.Errorf("more than one object matched gvk %s, ns: %q name: %q", gvk, ns, name) 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 // Only one object should match in the tracker if it works
@ -236,9 +220,6 @@ func (t *tracker) Get(gvk schema.GroupVersionKind, ns, name string) (runtime.Obj
} }
if status, ok := obj.(*metav1.Status); ok { if status, ok := obj.(*metav1.Status); ok {
if status.Details != nil {
status.Details.Kind = gvk.Kind
}
if status.Status != metav1.StatusSuccess { if status.Status != metav1.StatusSuccess {
return nil, &errors.StatusError{ErrStatus: *status} return nil, &errors.StatusError{ErrStatus: *status}
} }
@ -251,23 +232,10 @@ func (t *tracker) Add(obj runtime.Object) error {
if meta.IsListType(obj) { if meta.IsListType(obj) {
return t.addList(obj, false) return t.addList(obj, false)
} }
objMeta, err := meta.Accessor(obj) objMeta, err := meta.Accessor(obj)
if err != nil { if err != nil {
return err return err
} }
return t.add(obj, objMeta.GetNamespace(), false)
}
func (t *tracker) Create(obj runtime.Object, ns string) error {
return t.add(obj, ns, false)
}
func (t *tracker) Update(obj runtime.Object, ns string) error {
return t.add(obj, ns, true)
}
func (t *tracker) add(obj runtime.Object, ns string, replaceExisting bool) error {
gvks, _, err := t.scheme.ObjectKinds(obj) gvks, _, err := t.scheme.ObjectKinds(obj)
if err != nil { if err != nil {
return err return err
@ -275,25 +243,48 @@ func (t *tracker) add(obj runtime.Object, ns string, replaceExisting bool) error
if len(gvks) == 0 { if len(gvks) == 0 {
return fmt.Errorf("no registered kinds for %v", obj) 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) add(gvr schema.GroupVersionResource, obj runtime.Object, ns string, replaceExisting bool) error {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
for _, gvk := range gvks { gr := gvr.GroupResource()
gr := schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}
// To avoid the object from being accidentally modified by caller // To avoid the object from being accidentally modified by caller
// after it's been added to the tracker, we always store the deep // after it's been added to the tracker, we always store the deep
// copy. // copy.
obj, err = t.scheme.Copy(obj) obj, err := t.scheme.Copy(obj)
if err != nil { if err != nil {
return err return err
} }
if status, ok := obj.(*metav1.Status); ok && status.Details != nil {
gvk.Kind = status.Details.Kind
}
newMeta, err := meta.Accessor(obj) newMeta, err := meta.Accessor(obj)
if err != nil { if err != nil {
return err return err
@ -309,18 +300,14 @@ func (t *tracker) add(obj runtime.Object, ns string, replaceExisting bool) error
return errors.NewBadRequest(msg) return errors.NewBadRequest(msg)
} }
if err := checkNamespace(t.registry, gvk, newMeta.GetNamespace()); err != nil { for i, existingObj := range t.objects[gvr] {
return err
}
for i, existingObj := range t.objects[gvk] {
oldMeta, err := meta.Accessor(existingObj) oldMeta, err := meta.Accessor(existingObj)
if err != nil { if err != nil {
return err return err
} }
if oldMeta.GetNamespace() == newMeta.GetNamespace() && oldMeta.GetName() == newMeta.GetName() { if oldMeta.GetNamespace() == newMeta.GetNamespace() && oldMeta.GetName() == newMeta.GetName() {
if replaceExisting { if replaceExisting {
t.objects[gvk][i] = obj t.objects[gvr][i] = obj
return nil return nil
} }
return errors.NewAlreadyExists(gr, newMeta.GetName()) return errors.NewAlreadyExists(gr, newMeta.GetName())
@ -332,8 +319,7 @@ func (t *tracker) add(obj runtime.Object, ns string, replaceExisting bool) error
return errors.NewNotFound(gr, newMeta.GetName()) return errors.NewNotFound(gr, newMeta.GetName())
} }
t.objects[gvk] = append(t.objects[gvk], obj) t.objects[gvr] = append(t.objects[gvr], obj)
}
return nil return nil
} }
@ -348,35 +334,26 @@ func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error {
return errs[0] return errs[0]
} }
for _, obj := range list { for _, obj := range list {
objMeta, err := meta.Accessor(obj) if err := t.Add(obj); err != nil {
if err != nil {
return err
}
err = t.add(obj, objMeta.GetNamespace(), replaceExisting)
if err != nil {
return err return err
} }
} }
return nil return nil
} }
func (t *tracker) Delete(gvk schema.GroupVersionKind, ns, name string) error { func (t *tracker) Delete(gvr schema.GroupVersionResource, ns, name string) error {
if err := checkNamespace(t.registry, gvk, ns); err != nil {
return err
}
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
found := false found := false
for i, existingObj := range t.objects[gvk] { for i, existingObj := range t.objects[gvr] {
objMeta, err := meta.Accessor(existingObj) objMeta, err := meta.Accessor(existingObj)
if err != nil { if err != nil {
return err return err
} }
if objMeta.GetNamespace() == ns && objMeta.GetName() == name { if objMeta.GetNamespace() == ns && objMeta.GetName() == name {
t.objects[gvk] = append(t.objects[gvk][:i], t.objects[gvk][i+1:]...) t.objects[gvr] = append(t.objects[gvr][:i], t.objects[gvr][i+1:]...)
found = true found = true
break break
} }
@ -386,7 +363,7 @@ func (t *tracker) Delete(gvk schema.GroupVersionKind, ns, name string) error {
return nil return nil
} }
return errors.NewNotFound(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, name) return errors.NewNotFound(gvr.GroupResource(), name)
} }
// filterByNamespaceAndName returns all objects in the collection that // filterByNamespaceAndName returns all objects in the collection that
@ -412,37 +389,6 @@ func filterByNamespaceAndName(objs []runtime.Object, ns, name string) ([]runtime
return res, nil return res, nil
} }
// checkNamespace makes sure that the scope of gvk matches ns. It
// returns an error if namespace is empty but gvk is a namespaced
// kind, or if ns is non-empty and gvk is a namespaced kind.
func checkNamespace(registry *registered.APIRegistrationManager, gvk schema.GroupVersionKind, ns string) error {
group, err := registry.Group(gvk.Group)
if err != nil {
return err
}
mapping, err := group.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return err
}
switch mapping.Scope.Name() {
case meta.RESTScopeNameRoot:
if ns != "" {
return fmt.Errorf("namespace specified for a non-namespaced kind %s", gvk)
}
case meta.RESTScopeNameNamespace:
if ns == "" {
// Skipping this check for Events, since
// controllers emit events that have no namespace,
// even though Event is a namespaced resource.
if gvk.Kind != "Event" {
return fmt.Errorf("no namespace specified for a namespaced kind %s", gvk)
}
}
}
return nil
}
func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc { func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc {
return func(action Action) (bool, watch.Interface, error) { return func(action Action) (bool, watch.Interface, error) {
return true, watchInterface, err return true, watchInterface, err

View File

@ -33,7 +33,7 @@ import (
// without applying any validations and/or defaults. It shouldn't be considered a replacement // without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests. // for a real clientset and is mostly useful in simple unit tests.
func NewSimpleClientset(objects ...runtime.Object) *Clientset { func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(api.Registry, api.Scheme, api.Codecs.UniversalDecoder()) o := testing.NewObjectTracker(api.Scheme, api.Codecs.UniversalDecoder())
for _, obj := range objects { for _, obj := range objects {
if err := o.Add(obj); err != nil { if err := o.Add(obj); err != nil {
panic(err) panic(err)
@ -41,7 +41,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
} }
fakePtr := testing.Fake{} fakePtr := testing.Fake{}
fakePtr.AddReactor("*", "*", testing.ObjectReaction(o, api.Registry.RESTMapper())) fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil)) fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil))

View File

@ -32,6 +32,8 @@ type FakeNodeMetricses struct {
var nodemetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "nodemetricses"} var nodemetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "nodemetricses"}
var nodemetricsesKind = schema.GroupVersionKind{Group: "metrics", Version: "v1alpha1", Kind: "NodeMetrics"}
func (c *FakeNodeMetricses) Get(name string, options v1.GetOptions) (result *v1alpha1.NodeMetrics, err error) { func (c *FakeNodeMetricses) Get(name string, options v1.GetOptions) (result *v1alpha1.NodeMetrics, err error) {
obj, err := c.Fake. obj, err := c.Fake.
Invokes(testing.NewRootGetAction(nodemetricsesResource, name), &v1alpha1.NodeMetrics{}) Invokes(testing.NewRootGetAction(nodemetricsesResource, name), &v1alpha1.NodeMetrics{})
@ -43,7 +45,7 @@ func (c *FakeNodeMetricses) Get(name string, options v1.GetOptions) (result *v1a
func (c *FakeNodeMetricses) List(opts v1.ListOptions) (result *v1alpha1.NodeMetricsList, err error) { func (c *FakeNodeMetricses) List(opts v1.ListOptions) (result *v1alpha1.NodeMetricsList, err error) {
obj, err := c.Fake. obj, err := c.Fake.
Invokes(testing.NewRootListAction(nodemetricsesResource, opts), &v1alpha1.NodeMetricsList{}) Invokes(testing.NewRootListAction(nodemetricsesResource, nodemetricsesKind, opts), &v1alpha1.NodeMetricsList{})
if obj == nil { if obj == nil {
return nil, err return nil, err
} }

View File

@ -33,6 +33,8 @@ type FakePodMetricses struct {
var podmetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "podmetricses"} var podmetricsesResource = schema.GroupVersionResource{Group: "metrics", Version: "v1alpha1", Resource: "podmetricses"}
var podmetricsesKind = schema.GroupVersionKind{Group: "metrics", Version: "v1alpha1", Kind: "PodMetrics"}
func (c *FakePodMetricses) Get(name string, options v1.GetOptions) (result *v1alpha1.PodMetrics, err error) { func (c *FakePodMetricses) Get(name string, options v1.GetOptions) (result *v1alpha1.PodMetrics, err error) {
obj, err := c.Fake. obj, err := c.Fake.
Invokes(testing.NewGetAction(podmetricsesResource, c.ns, name), &v1alpha1.PodMetrics{}) Invokes(testing.NewGetAction(podmetricsesResource, c.ns, name), &v1alpha1.PodMetrics{})
@ -45,7 +47,7 @@ func (c *FakePodMetricses) Get(name string, options v1.GetOptions) (result *v1al
func (c *FakePodMetricses) List(opts v1.ListOptions) (result *v1alpha1.PodMetricsList, err error) { func (c *FakePodMetricses) List(opts v1.ListOptions) (result *v1alpha1.PodMetricsList, err error) {
obj, err := c.Fake. obj, err := c.Fake.
Invokes(testing.NewListAction(podmetricsesResource, c.ns, opts), &v1alpha1.PodMetricsList{}) Invokes(testing.NewListAction(podmetricsesResource, podmetricsesKind, c.ns, opts), &v1alpha1.PodMetricsList{})
if obj == nil { if obj == nil {
return nil, err return nil, err

View File

@ -19,9 +19,9 @@ package fake
import ( import (
"fmt" "fmt"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/testing" "k8s.io/client-go/testing"
"k8s.io/metrics/pkg/apis/custom_metrics/v1alpha1" "k8s.io/metrics/pkg/apis/custom_metrics/v1alpha1"
cmclient "k8s.io/metrics/pkg/client/custom_metrics" cmclient "k8s.io/metrics/pkg/client/custom_metrics"
@ -52,13 +52,12 @@ func (i GetForActionImpl) GetSubresource() string {
} }
func NewGetForAction(groupKind schema.GroupKind, namespace, name string, metricName string, labelSelector labels.Selector) GetForActionImpl { func NewGetForAction(groupKind schema.GroupKind, namespace, name string, metricName string, labelSelector labels.Selector) GetForActionImpl {
mapping, err := api.Registry.RESTMapper().RESTMapping(groupKind) // the version doesn't matter
if err != nil { gvk := groupKind.WithVersion("")
panic(fmt.Sprintf("unable to get REST mapping for groupKind %s while building GetFor action: %v", groupKind.String, err)) gvr, _ := meta.UnsafeGuessKindToResource(gvk)
}
groupResourceForKind := schema.GroupResource{ groupResourceForKind := schema.GroupResource{
Group: mapping.GroupVersionKind.Group, Group: gvr.Group,
Resource: mapping.Resource, Resource: gvr.Resource,
} }
resource := schema.GroupResource{ resource := schema.GroupResource{
Group: v1alpha1.SchemeGroupVersion.Group, Group: v1alpha1.SchemeGroupVersion.Group,
@ -72,13 +71,12 @@ func NewGetForAction(groupKind schema.GroupKind, namespace, name string, metricN
} }
func NewRootGetForAction(groupKind schema.GroupKind, name string, metricName string, labelSelector labels.Selector) GetForActionImpl { func NewRootGetForAction(groupKind schema.GroupKind, name string, metricName string, labelSelector labels.Selector) GetForActionImpl {
mapping, err := api.Registry.RESTMapper().RESTMapping(groupKind) // the version doesn't matter
if err != nil { gvk := groupKind.WithVersion("")
panic(fmt.Sprintf("unable to get REST mapping for groupKind %s while building GetFor action: %v", groupKind.String, err)) gvr, _ := meta.UnsafeGuessKindToResource(gvk)
}
groupResourceForKind := schema.GroupResource{ groupResourceForKind := schema.GroupResource{
Group: mapping.GroupVersionKind.Group, Group: gvr.Group,
Resource: mapping.Resource, Resource: gvr.Resource,
} }
resource := schema.GroupResource{ resource := schema.GroupResource{
Group: v1alpha1.SchemeGroupVersion.Group, Group: v1alpha1.SchemeGroupVersion.Group,