Add SelfLinker

This commit is contained in:
Daniel Smith 2014-09-25 14:57:41 -07:00
parent 3e6859564a
commit 75b93cf7e9
3 changed files with 112 additions and 5 deletions

View File

@ -40,6 +40,15 @@ type ResourceVersioner interface {
ResourceVersion(obj Object) (uint64, error) ResourceVersion(obj Object) (uint64, error)
} }
// SelfLinker provides methods for setting and retrieving the SelfLink field of an API object.
type SelfLinker interface {
SetSelfLink(obj Object, selfLink string) error
SelfLink(obj Object) (string, error)
// Knowing ID is sometimes necssary to use a SelfLinker.
ID(obj Object) (string, error)
}
// All api types must support the Object interface. It's deliberately tiny so that this is not an onerous // All api types must support the Object interface. It's deliberately tiny so that this is not an onerous
// burden. Implement it with a pointer reciever; this will allow us to use the go compiler to check the // burden. Implement it with a pointer reciever; this will allow us to use the go compiler to check the
// one thing about our objects that it's capable of checking for us. // one thing about our objects that it's capable of checking for us.

View File

@ -21,15 +21,16 @@ import (
"reflect" "reflect"
) )
// NewJSONBaseResourceVersioner returns a resourceVersioner that can set or // NewJSONBaseResourceVersioner returns a ResourceVersioner that can set or
// retrieve ResourceVersion on objects derived from JSONBase. // retrieve ResourceVersion on objects derived from JSONBase.
func NewJSONBaseResourceVersioner() ResourceVersioner { func NewJSONBaseResourceVersioner() ResourceVersioner {
return &jsonBaseResourceVersioner{} return jsonBaseModifier{}
} }
type jsonBaseResourceVersioner struct{} // jsonBaseModifier implements ResourceVersioner and SelfLinker.
type jsonBaseModifier struct{}
func (v jsonBaseResourceVersioner) ResourceVersion(obj Object) (uint64, error) { func (v jsonBaseModifier) ResourceVersion(obj Object) (uint64, error) {
json, err := FindJSONBase(obj) json, err := FindJSONBase(obj)
if err != nil { if err != nil {
return 0, err return 0, err
@ -37,7 +38,7 @@ func (v jsonBaseResourceVersioner) ResourceVersion(obj Object) (uint64, error) {
return json.ResourceVersion(), nil return json.ResourceVersion(), nil
} }
func (v jsonBaseResourceVersioner) SetResourceVersion(obj Object, version uint64) error { func (v jsonBaseModifier) SetResourceVersion(obj Object, version uint64) error {
json, err := FindJSONBase(obj) json, err := FindJSONBase(obj)
if err != nil { if err != nil {
return err return err
@ -46,6 +47,36 @@ func (v jsonBaseResourceVersioner) SetResourceVersion(obj Object, version uint64
return nil return nil
} }
func (v jsonBaseModifier) ID(obj Object) (string, error) {
json, err := FindJSONBase(obj)
if err != nil {
return "", err
}
return json.ID(), nil
}
func (v jsonBaseModifier) SelfLink(obj Object) (string, error) {
json, err := FindJSONBase(obj)
if err != nil {
return "", err
}
return json.SelfLink(), nil
}
func (v jsonBaseModifier) SetSelfLink(obj Object, selfLink string) error {
json, err := FindJSONBase(obj)
if err != nil {
return err
}
json.SetSelfLink(selfLink)
return nil
}
// NewJSONBaseSelfLinker returns a SelfLinker that works on all JSONBase SelfLink fields.
func NewJSONBaseSelfLinker() SelfLinker {
return jsonBaseModifier{}
}
// JSONBaseInterface lets you work with a JSONBase from any of the versioned or // JSONBaseInterface lets you work with a JSONBase from any of the versioned or
// internal APIObjects. // internal APIObjects.
type JSONBaseInterface interface { type JSONBaseInterface interface {
@ -57,6 +88,8 @@ type JSONBaseInterface interface {
SetKind(kind string) SetKind(kind string)
ResourceVersion() uint64 ResourceVersion() uint64
SetResourceVersion(version uint64) SetResourceVersion(version uint64)
SelfLink() string
SetSelfLink(selfLink string)
} }
type genericJSONBase struct { type genericJSONBase struct {
@ -64,6 +97,7 @@ type genericJSONBase struct {
apiVersion *string apiVersion *string
kind *string kind *string
resourceVersion *uint64 resourceVersion *uint64
selfLink *string
} }
func (g genericJSONBase) ID() string { func (g genericJSONBase) ID() string {
@ -98,6 +132,14 @@ func (g genericJSONBase) SetResourceVersion(version uint64) {
*g.resourceVersion = version *g.resourceVersion = version
} }
func (g genericJSONBase) SelfLink() string {
return *g.selfLink
}
func (g genericJSONBase) SetSelfLink(selfLink string) {
*g.selfLink = selfLink
}
// fieldPtr puts the address of fieldName, which must be a member of v, // fieldPtr puts the address of fieldName, which must be a member of v,
// into dest, which must be an address of a variable to which this field's // into dest, which must be an address of a variable to which this field's
// address can be assigned. // address can be assigned.
@ -140,5 +182,8 @@ func newGenericJSONBase(v reflect.Value) (genericJSONBase, error) {
if err := fieldPtr(v, "ResourceVersion", &g.resourceVersion); err != nil { if err := fieldPtr(v, "ResourceVersion", &g.resourceVersion); err != nil {
return g, err return g, err
} }
if err := fieldPtr(v, "SelfLink", &g.selfLink); err != nil {
return g, err
}
return g, nil return g, nil
} }

View File

@ -37,6 +37,7 @@ func TestGenericJSONBase(t *testing.T) {
APIVersion: "a", APIVersion: "a",
Kind: "b", Kind: "b",
ResourceVersion: 1, ResourceVersion: 1,
SelfLink: "some/place/only/we/know",
} }
g, err := newGenericJSONBase(reflect.ValueOf(&j).Elem()) g, err := newGenericJSONBase(reflect.ValueOf(&j).Elem())
if err != nil { if err != nil {
@ -56,11 +57,15 @@ func TestGenericJSONBase(t *testing.T) {
if e, a := uint64(1), jbi.ResourceVersion(); e != a { if e, a := uint64(1), jbi.ResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)
} }
if e, a := "some/place/only/we/know", jbi.SelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
jbi.SetID("bar") jbi.SetID("bar")
jbi.SetAPIVersion("c") jbi.SetAPIVersion("c")
jbi.SetKind("d") jbi.SetKind("d")
jbi.SetResourceVersion(2) jbi.SetResourceVersion(2)
jbi.SetSelfLink("google.com")
// Prove that jbi changes the original object. // Prove that jbi changes the original object.
if e, a := "bar", j.ID; e != a { if e, a := "bar", j.ID; e != a {
@ -75,6 +80,9 @@ func TestGenericJSONBase(t *testing.T) {
if e, a := uint64(2), j.ResourceVersion; e != a { if e, a := uint64(2), j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)
} }
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
} }
type MyAPIObject struct { type MyAPIObject struct {
@ -141,3 +149,48 @@ func TestResourceVersionerOfAPI(t *testing.T) {
} }
} }
} }
func TestJSONBaseSelfLinker(t *testing.T) {
table := map[string]struct {
obj Object
expect string
try string
succeed bool
}{
"normal": {
obj: &MyAPIObject{JSONBase: JSONBase{SelfLink: "foobar"}},
expect: "foobar",
try: "newbar",
succeed: true,
},
"fail": {
obj: &MyIncorrectlyMarkedAsAPIObject{},
succeed: false,
},
}
linker := NewJSONBaseSelfLinker()
for name, item := range table {
got, err := linker.SelfLink(item.obj)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if e, a := item.expect, got; item.succeed && e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
err = linker.SetSelfLink(item.obj, item.try)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if item.succeed {
got, err := linker.SelfLink(item.obj)
if err != nil {
t.Errorf("%v: expected no err, got %v", name, err)
}
if e, a := item.try, got; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
}
}
}