kubernetes/pkg/runtime/serializer/versioning/versioning_test.go
k8s-merge-robot 1ad3049ed6 Merge pull request #23288 from smarterclayton/refactor_codec
Auto commit by PR queue bot
2016-03-26 10:47:58 -07:00

301 lines
9.1 KiB
Go

/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 versioning
import (
"fmt"
"io"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/diff"
)
type testDecodable struct {
Other string
Value int `json:"value"`
gvk *unversioned.GroupVersionKind
}
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
func (d *testDecodable) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk }
func (d *testDecodable) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk }
func TestDecode(t *testing.T) {
gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
decodable1 := &testDecodable{}
decodable2 := &testDecodable{}
decodable3 := &testDecodable{}
versionedDecodable1 := &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}
testCases := []struct {
serializer runtime.Serializer
convertor runtime.ObjectConvertor
creater runtime.ObjectCreater
copier runtime.ObjectCopier
typer runtime.Typer
yaml bool
pretty bool
encodes, decodes []unversioned.GroupVersion
defaultGVK *unversioned.GroupVersionKind
into runtime.Object
errFn func(error) bool
expectedObject runtime.Object
sameObject runtime.Object
expectedGVK *unversioned.GroupVersionKind
}{
{
serializer: &mockSerializer{actual: gvk1},
convertor: &checkConvertor{groupVersion: "other/__internal"},
expectedGVK: gvk1,
},
{
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
expectedGVK: gvk1,
sameObject: decodable2,
},
// defaultGVK.Group is allowed to force a conversion to the destination group
{
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
defaultGVK: &unversioned.GroupVersionKind{Group: "force"},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "force/__internal"},
expectedGVK: gvk1,
sameObject: decodable2,
},
// uses direct conversion for into when objects differ
{
into: decodable3,
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable3, directConvert: true},
expectedGVK: gvk1,
sameObject: decodable3,
},
{
into: versionedDecodable1,
serializer: &mockSerializer{actual: gvk1, obj: decodable3},
convertor: &checkConvertor{in: decodable3, obj: decodable1, directConvert: true},
expectedGVK: gvk1,
sameObject: versionedDecodable1,
},
// returns directly when serializer returns into
{
into: decodable3,
serializer: &mockSerializer{actual: gvk1, obj: decodable3},
expectedGVK: gvk1,
sameObject: decodable3,
},
// returns directly when serializer returns into
{
into: versionedDecodable1,
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
expectedGVK: gvk1,
sameObject: versionedDecodable1,
},
// runtime.VersionedObjects are decoded
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
},
// decode into the same version as the serialized object
{
decodes: []unversioned.GroupVersion{gvk1.GroupVersion()},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
expectedGVK: gvk1,
expectedObject: decodable1,
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
decodes: []unversioned.GroupVersion{gvk1.GroupVersion()},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
},
// codec with non matching version skips conversion altogether
{
decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
expectedGVK: gvk1,
expectedObject: decodable1,
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
},
}
for i, test := range testCases {
t.Logf("%d", i)
s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.copier, test.typer, test.encodes, test.decodes)
obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into)
if !reflect.DeepEqual(test.expectedGVK, gvk) {
t.Errorf("%d: unexpected GVK: %v", i, gvk)
}
switch {
case err == nil && test.errFn != nil:
t.Errorf("%d: failed: %v", i, err)
continue
case err != nil && test.errFn == nil:
t.Errorf("%d: failed: %v", i, err)
continue
case err != nil:
if !test.errFn(err) {
t.Errorf("%d: failed: %v", i, err)
}
if obj != nil {
t.Errorf("%d: should have returned nil object", i)
}
continue
}
if test.into != nil && test.into != obj {
t.Errorf("%d: expected into to be returned: %v", i, obj)
continue
}
switch {
case test.expectedObject != nil:
if !reflect.DeepEqual(test.expectedObject, obj) {
t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
}
case test.sameObject != nil:
if test.sameObject != obj {
t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.sameObject, obj))
}
case obj != nil:
t.Errorf("%d: unexpected object: %#v", i, obj)
}
}
}
type checkCopy struct {
in, obj runtime.Object
err error
}
func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
if c.in != nil && c.in != obj {
return nil, fmt.Errorf("unexpected input to copy: %#v", obj)
}
return c.obj, c.err
}
type checkConvertor struct {
err error
in, obj runtime.Object
groupVersion string
directConvert bool
}
func (c *checkConvertor) Convert(in, out interface{}) error {
if !c.directConvert {
return fmt.Errorf("unexpected call to Convert")
}
if c.in != nil && c.in != in {
return fmt.Errorf("unexpected in: %s", in)
}
if c.obj != nil && c.obj != out {
return fmt.Errorf("unexpected out: %s", out)
}
return c.err
}
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion string) (out runtime.Object, err error) {
if c.directConvert {
return nil, fmt.Errorf("unexpected call to ConvertToVersion")
}
if c.in != nil && c.in != in {
return nil, fmt.Errorf("unexpected in: %s", in)
}
if c.groupVersion != outVersion {
return nil, fmt.Errorf("unexpected outversion: %s", outVersion)
}
return c.obj, c.err
}
func (c *checkConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
return "", "", fmt.Errorf("unexpected call to ConvertFieldLabel")
}
type mockSerializer struct {
err error
obj runtime.Object
versions []unversioned.GroupVersion
defaults, actual *unversioned.GroupVersionKind
into runtime.Object
}
func (s *mockSerializer) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
s.defaults = defaults
s.into = into
return s.obj, s.actual, s.err
}
func (s *mockSerializer) EncodeToStream(obj runtime.Object, w io.Writer, versions ...unversioned.GroupVersion) error {
s.obj = obj
s.versions = versions
return s.err
}
type mockCreater struct {
err error
obj runtime.Object
}
func (c *mockCreater) New(kind unversioned.GroupVersionKind) (runtime.Object, error) {
return c.obj, c.err
}
type mockTyper struct {
gvk *unversioned.GroupVersionKind
err error
}
func (t *mockTyper) ObjectKind(obj runtime.Object) (*unversioned.GroupVersionKind, bool, error) {
return t.gvk, false, t.err
}