Add SelfLinker

pull/6/head
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)
}
// 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
// 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.

View File

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

View File

@ -37,6 +37,7 @@ func TestGenericJSONBase(t *testing.T) {
APIVersion: "a",
Kind: "b",
ResourceVersion: 1,
SelfLink: "some/place/only/we/know",
}
g, err := newGenericJSONBase(reflect.ValueOf(&j).Elem())
if err != nil {
@ -56,11 +57,15 @@ func TestGenericJSONBase(t *testing.T) {
if e, a := uint64(1), jbi.ResourceVersion(); 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.SetAPIVersion("c")
jbi.SetKind("d")
jbi.SetResourceVersion(2)
jbi.SetSelfLink("google.com")
// Prove that jbi changes the original object.
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 {
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 {
@ -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)
}
}
}
}