2015-12-21 05:12:51 +00:00
|
|
|
/*
|
2016-06-03 00:25:58 +00:00
|
|
|
Copyright 2015 The Kubernetes Authors.
|
2015-12-21 05:12:51 +00:00
|
|
|
|
|
|
|
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 json_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"k8s.io/kubernetes/pkg/runtime"
|
2016-11-21 02:55:31 +00:00
|
|
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
2015-12-21 05:12:51 +00:00
|
|
|
"k8s.io/kubernetes/pkg/runtime/serializer/json"
|
2016-03-11 02:43:55 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/diff"
|
2015-12-21 05:12:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type testDecodable struct {
|
|
|
|
Other string
|
|
|
|
Value int `json:"value"`
|
2016-11-21 02:55:31 +00:00
|
|
|
gvk schema.GroupVersionKind
|
2015-12-21 05:12:51 +00:00
|
|
|
}
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
|
|
|
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
|
|
|
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
2015-12-21 05:12:51 +00:00
|
|
|
|
|
|
|
func TestDecode(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
creater runtime.ObjectCreater
|
2016-05-21 04:15:31 +00:00
|
|
|
typer runtime.ObjectTyper
|
2015-12-21 05:12:51 +00:00
|
|
|
yaml bool
|
|
|
|
pretty bool
|
|
|
|
|
|
|
|
data []byte
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK *schema.GroupVersionKind
|
2015-12-21 05:12:51 +00:00
|
|
|
into runtime.Object
|
|
|
|
|
|
|
|
errFn func(error) bool
|
|
|
|
expectedObject runtime.Object
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK *schema.GroupVersionKind
|
2015-12-21 05:12:51 +00:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
data: []byte("{}"),
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{},
|
2015-12-21 05:12:51 +00:00
|
|
|
errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: []byte("{}"),
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
creater: &mockCreater{err: fmt.Errorf("fake error")},
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
errFn: func(err error) bool { return err.Error() == "fake error" },
|
|
|
|
},
|
|
|
|
{
|
2016-05-01 00:34:40 +00:00
|
|
|
data: []byte("{}"),
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2016-05-01 00:34:40 +00:00
|
|
|
creater: &mockCreater{obj: &testDecodable{}},
|
|
|
|
expectedObject: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// version without group is not defaulted
|
|
|
|
{
|
2016-05-01 00:34:40 +00:00
|
|
|
data: []byte(`{"apiVersion":"blah"}`),
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2016-05-01 00:34:40 +00:00
|
|
|
creater: &mockCreater{obj: &testDecodable{}},
|
|
|
|
expectedObject: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
// group without version is defaulted
|
|
|
|
{
|
2016-05-01 00:34:40 +00:00
|
|
|
data: []byte(`{"apiVersion":"other/"}`),
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2016-05-01 00:34:40 +00:00
|
|
|
creater: &mockCreater{obj: &testDecodable{}},
|
|
|
|
expectedObject: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// accept runtime.Unknown as into and bypass creator
|
|
|
|
{
|
|
|
|
data: []byte(`{}`),
|
|
|
|
into: &runtime.Unknown{},
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &runtime.Unknown{
|
2016-03-16 08:03:33 +00:00
|
|
|
Raw: []byte(`{}`),
|
|
|
|
ContentType: runtime.ContentTypeJSON,
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: []byte(`{"test":"object"}`),
|
|
|
|
into: &runtime.Unknown{},
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
expectedGVK: &schema.GroupVersionKind{},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &runtime.Unknown{
|
2016-03-16 08:03:33 +00:00
|
|
|
Raw: []byte(`{"test":"object"}`),
|
|
|
|
ContentType: runtime.ContentTypeJSON,
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: []byte(`{"test":"object"}`),
|
|
|
|
into: &runtime.Unknown{},
|
2016-11-21 02:55:31 +00:00
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &runtime.Unknown{
|
2016-03-16 08:03:33 +00:00
|
|
|
TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"},
|
|
|
|
Raw: []byte(`{"test":"object"}`),
|
|
|
|
ContentType: runtime.ContentTypeJSON,
|
2015-12-21 05:12:51 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// unregistered objects can be decoded into directly
|
|
|
|
{
|
|
|
|
data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`),
|
|
|
|
into: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
typer: &mockTyper{err: runtime.NewNotRegisteredErr(schema.GroupVersionKind{}, nil)},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &testDecodable{
|
|
|
|
Other: "test",
|
|
|
|
Value: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// registered types get defaulted by the into object kind
|
|
|
|
{
|
|
|
|
data: []byte(`{"value":1,"Other":"test"}`),
|
|
|
|
into: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &testDecodable{
|
|
|
|
Other: "test",
|
|
|
|
Value: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// registered types get defaulted by the into object kind even without version, but return an error
|
|
|
|
{
|
|
|
|
data: []byte(`{"value":1,"Other":"test"}`),
|
|
|
|
into: &testDecodable{},
|
2016-11-21 02:55:31 +00:00
|
|
|
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""},
|
2015-12-21 05:12:51 +00:00
|
|
|
errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'apiVersion' is missing in") },
|
|
|
|
expectedObject: &testDecodable{
|
|
|
|
Other: "test",
|
|
|
|
Value: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// runtime.VersionedObjects are decoded
|
|
|
|
{
|
|
|
|
data: []byte(`{"value":1,"Other":"test"}`),
|
|
|
|
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
|
|
|
|
creater: &mockCreater{obj: &testDecodable{}},
|
2016-11-21 02:55:31 +00:00
|
|
|
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
|
|
|
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &runtime.VersionedObjects{
|
|
|
|
Objects: []runtime.Object{
|
|
|
|
&testDecodable{
|
|
|
|
Other: "test",
|
|
|
|
Value: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// runtime.VersionedObjects with an object are decoded into
|
|
|
|
{
|
|
|
|
data: []byte(`{"Other":"test"}`),
|
|
|
|
into: &runtime.VersionedObjects{Objects: []runtime.Object{&testDecodable{Value: 2}}},
|
2016-11-21 02:55:31 +00:00
|
|
|
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
|
|
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
2015-12-21 05:12:51 +00:00
|
|
|
expectedObject: &runtime.VersionedObjects{
|
|
|
|
Objects: []runtime.Object{
|
|
|
|
&testDecodable{
|
|
|
|
Other: "test",
|
|
|
|
Value: 2,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range testCases {
|
|
|
|
var s runtime.Serializer
|
|
|
|
if test.yaml {
|
|
|
|
s = json.NewYAMLSerializer(json.DefaultMetaFactory, test.creater, test.typer)
|
|
|
|
} else {
|
|
|
|
s = json.NewSerializer(json.DefaultMetaFactory, test.creater, test.typer, test.pretty)
|
|
|
|
}
|
|
|
|
obj, gvk, err := s.Decode([]byte(test.data), 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
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(test.expectedObject, obj) {
|
2016-03-11 02:43:55 +00:00
|
|
|
t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
|
2015-12-21 05:12:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockCreater struct {
|
|
|
|
apiVersion string
|
|
|
|
kind string
|
|
|
|
err error
|
|
|
|
obj runtime.Object
|
|
|
|
}
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
2015-12-21 05:12:51 +00:00
|
|
|
c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind
|
|
|
|
return c.obj, c.err
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockTyper struct {
|
2016-11-21 02:55:31 +00:00
|
|
|
gvk *schema.GroupVersionKind
|
2015-12-21 05:12:51 +00:00
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
2016-05-21 04:15:31 +00:00
|
|
|
if t.gvk == nil {
|
|
|
|
return nil, false, t.err
|
|
|
|
}
|
2016-11-21 02:55:31 +00:00
|
|
|
return []schema.GroupVersionKind{*t.gvk}, false, t.err
|
2016-05-21 04:15:31 +00:00
|
|
|
}
|
|
|
|
|
2016-11-21 02:55:31 +00:00
|
|
|
func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool {
|
2016-05-21 04:15:31 +00:00
|
|
|
return false
|
2015-12-21 05:12:51 +00:00
|
|
|
}
|