vendor: remove dep and use vndr

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2017-06-06 09:19:04 +02:00
parent 16f44674a4
commit 148e72d81e
No known key found for this signature in database
GPG key ID: B2BEAD150DE936B9
16131 changed files with 73815 additions and 4235138 deletions

View file

@ -1,19 +0,0 @@
approvers:
- caesarxuchao
- deads2k
- lavalamp
- smarterclayton
reviewers:
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- derekwaynecarr
- caesarxuchao
- mikedanese
- nikhiljindal
- gmarek
- krousey
- timothysc
- piosz
- mbohlool

View file

@ -161,11 +161,12 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from schema.Gro
if err != nil {
return err
}
targetGVK := targetGVKs[0]
if targetGVK.GroupVersion() == from {
return c.convertor.Convert(&parameters, into, nil)
for i := range targetGVKs {
if targetGVKs[i].GroupVersion() == from {
return c.convertor.Convert(&parameters, into, nil)
}
}
input, err := c.creator.New(from.WithKind(targetGVK.Kind))
input, err := c.creator.New(from.WithKind(targetGVKs[0].Kind))
if err != nil {
return err
}
@ -194,16 +195,17 @@ func (c *parameterCodec) EncodeParameters(obj Object, to schema.GroupVersion) (u
}
type base64Serializer struct {
Serializer
Encoder
Decoder
}
func NewBase64Serializer(s Serializer) Serializer {
return &base64Serializer{s}
func NewBase64Serializer(e Encoder, d Decoder) Serializer {
return &base64Serializer{e, d}
}
func (s base64Serializer) Encode(obj Object, stream io.Writer) error {
e := base64.NewEncoder(base64.StdEncoding, stream)
err := s.Serializer.Encode(obj, e)
err := s.Encoder.Encode(obj, e)
e.Close()
return err
}
@ -214,7 +216,7 @@ func (s base64Serializer) Decode(data []byte, defaults *schema.GroupVersionKind,
if err != nil {
return nil, nil, err
}
return s.Serializer.Decode(out[:n], defaults, into)
return s.Decoder.Decode(out[:n], defaults, into)
}
// SerializerInfoForMediaType returns the first info in types that has a matching media type (which cannot

View file

@ -1,135 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 runtime_test
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type InternalComplex struct {
runtime.TypeMeta
String string
Integer int
Integer64 int64
Int64 int64
Bool bool
}
type ExternalComplex struct {
runtime.TypeMeta `json:",inline"`
String string `json:"string" description:"testing"`
Integer int `json:"int"`
Integer64 int64 `json:",omitempty"`
Int64 int64
Bool bool `json:"bool"`
}
func (obj *InternalComplex) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ExternalComplex) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func TestStringMapConversion(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "external"}
scheme := runtime.NewScheme()
scheme.Log(t)
scheme.AddKnownTypeWithName(internalGV.WithKind("Complex"), &InternalComplex{})
scheme.AddKnownTypeWithName(externalGV.WithKind("Complex"), &ExternalComplex{})
testCases := map[string]struct {
input map[string][]string
errFn func(error) bool
expected runtime.Object
}{
"ignores omitempty": {
input: map[string][]string{
"String": {"not_used"},
"string": {"value"},
"int": {"1"},
"Integer64": {"2"},
},
expected: &ExternalComplex{String: "value", Integer: 1},
},
"returns error on bad int": {
input: map[string][]string{
"int": {"a"},
},
errFn: func(err error) bool { return err != nil },
expected: &ExternalComplex{},
},
"parses int64": {
input: map[string][]string{
"Int64": {"-1"},
},
expected: &ExternalComplex{Int64: -1},
},
"returns error on bad int64": {
input: map[string][]string{
"Int64": {"a"},
},
errFn: func(err error) bool { return err != nil },
expected: &ExternalComplex{},
},
"parses boolean true": {
input: map[string][]string{
"bool": {"true"},
},
expected: &ExternalComplex{Bool: true},
},
"parses boolean any value": {
input: map[string][]string{
"bool": {"foo"},
},
expected: &ExternalComplex{Bool: true},
},
"parses boolean false": {
input: map[string][]string{
"bool": {"false"},
},
expected: &ExternalComplex{Bool: false},
},
"parses boolean empty value": {
input: map[string][]string{
"bool": {""},
},
expected: &ExternalComplex{Bool: true},
},
"parses boolean no value": {
input: map[string][]string{
"bool": {},
},
expected: &ExternalComplex{Bool: false},
},
}
for k, tc := range testCases {
out := &ExternalComplex{}
if err := scheme.Convert(&tc.input, out, nil); (tc.errFn == nil && err != nil) || (tc.errFn != nil && !tc.errFn(err)) {
t.Errorf("%s: unexpected error: %v", k, err)
continue
} else if err != nil {
continue
}
if !reflect.DeepEqual(out, tc.expected) {
t.Errorf("%s: unexpected output: %#v", k, out)
}
}
}

View file

@ -1,290 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 runtime_test
import (
"encoding/json"
"reflect"
"strings"
"testing"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/diff"
)
type EmbeddedTest struct {
runtime.TypeMeta
ID string
Object runtime.Object
EmptyObject runtime.Object
}
type EmbeddedTestExternal struct {
runtime.TypeMeta `json:",inline"`
ID string `json:"id,omitempty"`
Object runtime.RawExtension `json:"object,omitempty"`
EmptyObject runtime.RawExtension `json:"emptyObject,omitempty"`
}
type ObjectTest struct {
runtime.TypeMeta
ID string
Items []runtime.Object
}
type ObjectTestExternal struct {
runtime.TypeMeta `yaml:",inline" json:",inline"`
ID string `json:"id,omitempty"`
Items []runtime.RawExtension `json:"items,omitempty"`
}
func (obj *ObjectTest) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ObjectTestExternal) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *EmbeddedTest) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *EmbeddedTestExternal) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
externalGVK := externalGV.WithKind("ObjectTest")
s := runtime.NewScheme()
s.AddKnownTypes(internalGV, &ObjectTest{})
s.AddKnownTypeWithName(externalGVK, &ObjectTestExternal{})
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
obj, gvk, err := codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{}]}`), nil, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
test := obj.(*ObjectTest)
if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != "{}" || unk.ContentType != runtime.ContentTypeJSON {
t.Fatalf("unexpected object: %#v", test.Items[0])
}
if *gvk != externalGVK {
t.Fatalf("unexpected kind: %#v", gvk)
}
obj, gvk, err = codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{"kind":"Other","apiVersion":"v1"}]}`), nil, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
test = obj.(*ObjectTest)
if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != `{"kind":"Other","apiVersion":"v1"}` || unk.ContentType != runtime.ContentTypeJSON {
t.Fatalf("unexpected object: %#v", test.Items[0])
}
if *gvk != externalGVK {
t.Fatalf("unexpected kind: %#v", gvk)
}
}
func TestArrayOfRuntimeObject(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
s := runtime.NewScheme()
s.AddKnownTypes(internalGV, &EmbeddedTest{})
s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &EmbeddedTestExternal{})
s.AddKnownTypes(internalGV, &ObjectTest{})
s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &ObjectTestExternal{})
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
innerItems := []runtime.Object{
&EmbeddedTest{ID: "baz"},
}
items := []runtime.Object{
&EmbeddedTest{ID: "foo"},
&EmbeddedTest{ID: "bar"},
// TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization
&runtime.Unknown{
Raw: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`),
ContentType: runtime.ContentTypeJSON,
},
&ObjectTest{
Items: runtime.NewEncodableList(codec, innerItems),
},
}
internal := &ObjectTest{
Items: runtime.NewEncodableList(codec, items),
}
wire, err := runtime.Encode(codec, internal)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
t.Logf("Wire format is:\n%s\n", string(wire))
obj := &ObjectTestExternal{}
if err := json.Unmarshal(wire, obj); err != nil {
t.Fatalf("unexpected error: %v", err)
}
t.Logf("exact wire is: %s", string(obj.Items[0].Raw))
items[3] = &ObjectTest{Items: innerItems}
internal.Items = items
decoded, err := runtime.Decode(codec, wire)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
list, err := meta.ExtractList(decoded)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if errs := runtime.DecodeList(list, codec); len(errs) > 0 {
t.Fatalf("unexpected error: %v", errs)
}
list2, err := meta.ExtractList(list[3])
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if errs := runtime.DecodeList(list2, codec); len(errs) > 0 {
t.Fatalf("unexpected error: %v", errs)
}
if err := meta.SetList(list[3], list2); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// we want DecodeList to set type meta if possible, even on runtime.Unknown objects
internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"}
if e, a := internal.Items, list; !reflect.DeepEqual(e, a) {
t.Errorf("mismatched decoded: %s", diff.ObjectGoPrintSideBySide(e, a))
}
}
func TestNestedObject(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
s := runtime.NewScheme()
s.AddKnownTypes(internalGV, &EmbeddedTest{})
s.AddKnownTypeWithName(embeddedTestExternalGVK, &EmbeddedTestExternal{})
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
inner := &EmbeddedTest{
ID: "inner",
}
outer := &EmbeddedTest{
ID: "outer",
Object: runtime.NewEncodable(codec, inner),
}
wire, err := runtime.Encode(codec, outer)
if err != nil {
t.Fatalf("Unexpected encode error '%v'", err)
}
t.Logf("Wire format is:\n%v\n", string(wire))
decoded, err := runtime.Decode(codec, wire)
if err != nil {
t.Fatalf("Unexpected decode error %v", err)
}
// for later tests
outer.Object = inner
if e, a := outer, decoded; reflect.DeepEqual(e, a) {
t.Errorf("Expected unequal %#v %#v", e, a)
}
obj, err := runtime.Decode(codec, decoded.(*EmbeddedTest).Object.(*runtime.Unknown).Raw)
if err != nil {
t.Fatal(err)
}
decoded.(*EmbeddedTest).Object = obj
if e, a := outer, decoded; !reflect.DeepEqual(e, a) {
t.Errorf("Expected equal %#v %#v", e, a)
}
// test JSON decoding of the external object, which should preserve
// raw bytes
var externalViaJSON EmbeddedTestExternal
err = json.Unmarshal(wire, &externalViaJSON)
if err != nil {
t.Fatalf("Unexpected decode error %v", err)
}
if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" {
t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON)
}
if !reflect.DeepEqual(externalViaJSON.EmptyObject.Raw, []byte("null")) || len(externalViaJSON.Object.Raw) == 0 {
t.Errorf("Expected deserialization of nested objects into bytes, got %#v", externalViaJSON)
}
// test JSON decoding, too, since Decode uses yaml unmarshalling.
// Generic Unmarshalling of JSON cannot load the nested objects because there is
// no default schema set. Consumers wishing to get direct JSON decoding must use
// the external representation
var decodedViaJSON EmbeddedTest
err = json.Unmarshal(wire, &decodedViaJSON)
if err == nil || !strings.Contains(err.Error(), "unmarshal object into Go value of type runtime.Object") {
t.Fatalf("Unexpected decode error %v", err)
}
if a := decodedViaJSON; a.Object != nil || a.EmptyObject != nil {
t.Errorf("Expected embedded objects to be nil: %#v", a)
}
}
// TestDeepCopyOfRuntimeObject checks to make sure that runtime.Objects's can be passed through DeepCopy with fidelity
func TestDeepCopyOfRuntimeObject(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
s := runtime.NewScheme()
s.AddKnownTypes(internalGV, &EmbeddedTest{})
s.AddKnownTypeWithName(embeddedTestExternalGVK, &EmbeddedTestExternal{})
original := &EmbeddedTest{
ID: "outer",
Object: &EmbeddedTest{
ID: "inner",
},
}
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
originalData, err := runtime.Encode(codec, original)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
t.Logf("originalRole = %v\n", string(originalData))
copyOfOriginal, err := s.DeepCopy(original)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
copiedData, err := runtime.Encode(codec, copyOfOriginal.(runtime.Object))
if err != nil {
t.Errorf("unexpected error: %v", err)
}
t.Logf("copyOfRole = %v\n", string(copiedData))
if !reflect.DeepEqual(original, copyOfOriginal) {
t.Errorf("expected \n%v\n, got \n%v", string(originalData), string(copiedData))
}
}

View file

@ -1,39 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 runtime_test
import (
"encoding/json"
"testing"
"k8s.io/apimachinery/pkg/runtime"
)
func TestEmbeddedRawExtensionMarshal(t *testing.T) {
type test struct {
Ext runtime.RawExtension
}
extension := test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}}
data, err := json.Marshal(extension)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if string(data) != `{"Ext":{"foo":"bar"}}` {
t.Errorf("unexpected data: %s", string(data))
}
}

View file

@ -1,136 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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 schema
import (
"testing"
)
func TestGroupVersionParse(t *testing.T) {
tests := []struct {
input string
out GroupVersion
err func(error) bool
}{
{input: "v1", out: GroupVersion{Version: "v1"}},
{input: "v2", out: GroupVersion{Version: "v2"}},
{input: "/v1", out: GroupVersion{Version: "v1"}},
{input: "v1/", out: GroupVersion{Group: "v1"}},
{input: "/v1/", err: func(err error) bool { return err.Error() == "unexpected GroupVersion string: /v1/" }},
{input: "v1/a", out: GroupVersion{Group: "v1", Version: "a"}},
}
for i, test := range tests {
out, err := ParseGroupVersion(test.input)
if test.err == nil && err != nil || err == nil && test.err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if test.err != nil && !test.err(err) {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if out != test.out {
t.Errorf("%d: unexpected output: %#v", i, out)
}
}
}
func TestGroupResourceParse(t *testing.T) {
tests := []struct {
input string
out GroupResource
}{
{input: "v1", out: GroupResource{Resource: "v1"}},
{input: ".v1", out: GroupResource{Group: "v1"}},
{input: "v1.", out: GroupResource{Resource: "v1"}},
{input: "v1.a", out: GroupResource{Group: "a", Resource: "v1"}},
{input: "b.v1.a", out: GroupResource{Group: "v1.a", Resource: "b"}},
}
for i, test := range tests {
out := ParseGroupResource(test.input)
if out != test.out {
t.Errorf("%d: unexpected output: %#v", i, out)
}
}
}
func TestParseResourceArg(t *testing.T) {
tests := []struct {
input string
gvr *GroupVersionResource
gr GroupResource
}{
{input: "v1", gr: GroupResource{Resource: "v1"}},
{input: ".v1", gr: GroupResource{Group: "v1"}},
{input: "v1.", gr: GroupResource{Resource: "v1"}},
{input: "v1.a", gr: GroupResource{Group: "a", Resource: "v1"}},
{input: "b.v1.a", gvr: &GroupVersionResource{Group: "a", Version: "v1", Resource: "b"}, gr: GroupResource{Group: "v1.a", Resource: "b"}},
}
for i, test := range tests {
gvr, gr := ParseResourceArg(test.input)
if (gvr != nil && test.gvr == nil) || (gvr == nil && test.gvr != nil) || (test.gvr != nil && *gvr != *test.gvr) {
t.Errorf("%d: unexpected output: %#v", i, gvr)
}
if gr != test.gr {
t.Errorf("%d: unexpected output: %#v", i, gr)
}
}
}
func TestKindForGroupVersionKinds(t *testing.T) {
gvks := GroupVersions{
GroupVersion{Group: "batch", Version: "v1"},
GroupVersion{Group: "batch", Version: "v2alpha1"},
GroupVersion{Group: "policy", Version: "v1beta1"},
}
cases := []struct {
input []GroupVersionKind
target GroupVersionKind
ok bool
}{
{
input: []GroupVersionKind{{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}},
target: GroupVersionKind{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"},
ok: true,
},
{
input: []GroupVersionKind{{Group: "batch", Version: "v3alpha1", Kind: "CronJob"}},
target: GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"},
ok: true,
},
{
input: []GroupVersionKind{{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"}},
target: GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"},
ok: true,
},
{
input: []GroupVersionKind{{Group: "apps", Version: "v1alpha1", Kind: "StatefulSet"}},
target: GroupVersionKind{},
ok: false,
},
}
for i, c := range cases {
target, ok := gvks.KindForGroupVersionKinds(c.input)
if c.target != target {
t.Errorf("%d: unexpected target: %v, expected %v", i, target, c.target)
}
if c.ok != ok {
t.Errorf("%d: unexpected ok: %v, expected %v", i, ok, c.ok)
}
}
}

View file

@ -163,22 +163,13 @@ func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Objec
// the struct becomes the "kind" field when encoding. Version may not be empty - use the
// APIVersionInternal constant if you have a type that does not have a formal version.
func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) {
if len(gv.Version) == 0 {
panic(fmt.Sprintf("version is required on all types: %s %v", gv, types[0]))
}
for _, obj := range types {
t := reflect.TypeOf(obj)
if t.Kind() != reflect.Ptr {
panic("All types must be pointers to structs.")
}
t = t.Elem()
if t.Kind() != reflect.Struct {
panic("All types must be pointers to structs.")
}
gvk := gv.WithKind(t.Name())
s.gvkToType[gvk] = t
s.typeToGVK[t] = append(s.typeToGVK[t], gvk)
s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj)
}
}
@ -199,7 +190,17 @@ func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) {
panic("All types must be pointers to structs.")
}
if oldT, found := s.gvkToType[gvk]; found && oldT != t {
panic(fmt.Sprintf("Double registration of different types for %v: old=%v.%v, new=%v.%v", gvk, oldT.PkgPath(), oldT.Name(), t.PkgPath(), t.Name()))
}
s.gvkToType[gvk] = t
for _, existingGvk := range s.typeToGVK[t] {
if existingGvk == gvk {
return
}
}
s.typeToGVK[t] = append(s.typeToGVK[t], gvk)
}

View file

@ -1,925 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 runtime_test
import (
"reflect"
"strings"
"testing"
"github.com/google/gofuzz"
flag "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/diff"
)
var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
type InternalSimple struct {
runtime.TypeMeta `json:",inline"`
TestString string `json:"testString"`
}
type ExternalSimple struct {
runtime.TypeMeta `json:",inline"`
TestString string `json:"testString"`
}
func (obj *InternalSimple) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ExternalSimple) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func TestScheme(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{})
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{})
// If set, would clear TypeMeta during conversion.
//scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{})
// test that scheme is an ObjectTyper
var _ runtime.ObjectTyper = scheme
internalToExternalCalls := 0
externalToInternalCalls := 0
// Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++
return nil
},
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0)
externalToInternalCalls++
return nil
},
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
codecs := serializer.NewCodecFactory(scheme)
codec := codecs.LegacyCodec(externalGV)
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
jsonserializer := info.Serializer
simple := &InternalSimple{
TestString: "foo",
}
// Test Encode, Decode, DecodeInto, and DecodeToVersion
obj := runtime.Object(simple)
data, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj2.(*InternalSimple); !ok {
t.Fatalf("Got wrong type")
}
if e, a := simple, obj2; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj3 := &InternalSimple{}
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Fatal(err)
}
// clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion
// does not automatically clear TypeMeta anymore).
simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()}
if e, a := simple, obj3; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj4, err := runtime.Decode(jsonserializer, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj4.(*ExternalSimple); !ok {
t.Fatalf("Got wrong type")
}
// Test Convert
external := &ExternalSimple{}
err = scheme.Convert(simple, external, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// Encode and Convert should each have caused an increment.
if e, a := 2, internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// DecodeInto and Decode should each have caused an increment because of a conversion
if e, a := 2, externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
func TestBadJSONRejection(t *testing.T) {
scheme := runtime.NewScheme()
codecs := serializer.NewCodecFactory(scheme)
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
jsonserializer := info.Serializer
badJSONMissingKind := []byte(`{ }`)
if _, err := runtime.Decode(jsonserializer, badJSONMissingKind); err == nil {
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
}
badJSONUnknownType := []byte(`{"kind": "bar"}`)
if _, err1 := runtime.Decode(jsonserializer, badJSONUnknownType); err1 == nil {
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
}
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
if err2 := DecodeInto(badJSONKindMismatch, &Node{}); err2 == nil {
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
}*/
}
type ExtensionA struct {
runtime.TypeMeta `json:",inline"`
TestString string `json:"testString"`
}
type ExtensionB struct {
runtime.TypeMeta `json:",inline"`
TestString string `json:"testString"`
}
type ExternalExtensionType struct {
runtime.TypeMeta `json:",inline"`
Extension runtime.RawExtension `json:"extension"`
}
type InternalExtensionType struct {
runtime.TypeMeta `json:",inline"`
Extension runtime.Object `json:"extension"`
}
type ExternalOptionalExtensionType struct {
runtime.TypeMeta `json:",inline"`
Extension runtime.RawExtension `json:"extension,omitempty"`
}
type InternalOptionalExtensionType struct {
runtime.TypeMeta `json:",inline"`
Extension runtime.Object `json:"extension,omitempty"`
}
func (obj *ExtensionA) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ExtensionB) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ExternalExtensionType) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *InternalExtensionType) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ExternalOptionalExtensionType) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *InternalOptionalExtensionType) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func TestExternalToInternalMapping(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{})
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
table := []struct {
obj runtime.Object
encoded string
}{
{
&InternalOptionalExtensionType{Extension: nil},
`{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`,
},
}
for i, item := range table {
gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
if err != nil {
t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
} else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) {
t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
}
}
}
func TestExtensionMapping(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &InternalExtensionType{})
scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &ExternalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{})
// register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the
// external version.
scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &ExtensionA{})
scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &ExtensionB{})
scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &ExtensionA{})
scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &ExtensionB{})
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
table := []struct {
obj runtime.Object
expected runtime.Object
encoded string
}{
{
&InternalExtensionType{
Extension: runtime.NewEncodable(codec, &ExtensionA{TestString: "foo"}),
},
&InternalExtensionType{
Extension: &runtime.Unknown{
Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`),
ContentType: runtime.ContentTypeJSON,
},
},
// apiVersion is set in the serialized object for easier consumption by clients
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}}
`,
}, {
&InternalExtensionType{Extension: runtime.NewEncodable(codec, &ExtensionB{TestString: "bar"})},
&InternalExtensionType{
Extension: &runtime.Unknown{
Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`),
ContentType: runtime.ContentTypeJSON,
},
},
// apiVersion is set in the serialized object for easier consumption by clients
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}}
`,
}, {
&InternalExtensionType{Extension: nil},
&InternalExtensionType{
Extension: nil,
},
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null}
`,
},
}
for i, item := range table {
gotEncoded, err := runtime.Encode(codec, item.obj)
if err != nil {
t.Errorf("unexpected error '%v' (%#v)", err, item.obj)
} else if e, a := item.encoded, string(gotEncoded); e != a {
t.Errorf("expected\n%#v\ngot\n%#v\n", e, a)
}
gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
if err != nil {
t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
} else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) {
t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
}
}
}
func TestEncode(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{})
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{})
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
test := &InternalSimple{
TestString: "I'm the same",
}
obj := runtime.Object(test)
data, err := runtime.Encode(codec, obj)
obj2, gvk, err2 := codec.Decode(data, nil, nil)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
if _, ok := obj2.(*InternalSimple); !ok {
t.Fatalf("Got wrong type")
}
if !reflect.DeepEqual(obj2, test) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
}
if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("unexpected gvk returned by decode: %#v", gvk)
}
}
func TestUnversionedTypes(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
otherGV := schema.GroupVersion{Group: "group", Version: "other"}
scheme := runtime.NewScheme()
scheme.AddUnversionedTypes(externalGV, &InternalSimple{})
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{})
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{})
scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &ExternalSimple{})
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
if unv, ok := scheme.IsUnversioned(&InternalSimple{}); !unv || !ok {
t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok)
}
kinds, _, err := scheme.ObjectKinds(&InternalSimple{})
if err != nil {
t.Fatal(err)
}
kind := kinds[0]
if kind != externalGV.WithKind("InternalSimple") {
t.Fatalf("unexpected: %#v", kind)
}
test := &InternalSimple{
TestString: "I'm the same",
}
obj := runtime.Object(test)
data, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
obj2, gvk, err := codec.Decode(data, nil, nil)
if err != nil {
t.Fatal(err)
}
if _, ok := obj2.(*InternalSimple); !ok {
t.Fatalf("Got wrong type")
}
if !reflect.DeepEqual(obj2, test) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
}
// object is serialized as an unversioned object (in the group and version it was defined in)
if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "InternalSimple"}) {
t.Errorf("unexpected gvk returned by decode: %#v", gvk)
}
// when serialized to a different group, the object is kept in its preferred name
codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV)
data, err = runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" {
t.Errorf("unexpected data: %s", data)
}
}
// Test a weird version/kind embedding format.
type MyWeirdCustomEmbeddedVersionKindField struct {
ID string `json:"ID,omitempty"`
APIVersion string `json:"myVersionKey,omitempty"`
ObjectKind string `json:"myKindKey,omitempty"`
Z string `json:"Z,omitempty"`
Y uint64 `json:"Y,omitempty"`
}
type TestType1 struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
C int8 `json:"C,omitempty"`
D int16 `json:"D,omitempty"`
E int32 `json:"E,omitempty"`
F int64 `json:"F,omitempty"`
G uint `json:"G,omitempty"`
H uint8 `json:"H,omitempty"`
I uint16 `json:"I,omitempty"`
J uint32 `json:"J,omitempty"`
K uint64 `json:"K,omitempty"`
L bool `json:"L,omitempty"`
M map[string]int `json:"M,omitempty"`
N map[string]TestType2 `json:"N,omitempty"`
O *TestType2 `json:"O,omitempty"`
P []TestType2 `json:"Q,omitempty"`
}
type TestType2 struct {
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
}
type ExternalTestType2 struct {
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
}
type ExternalTestType1 struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
C int8 `json:"C,omitempty"`
D int16 `json:"D,omitempty"`
E int32 `json:"E,omitempty"`
F int64 `json:"F,omitempty"`
G uint `json:"G,omitempty"`
H uint8 `json:"H,omitempty"`
I uint16 `json:"I,omitempty"`
J uint32 `json:"J,omitempty"`
K uint64 `json:"K,omitempty"`
L bool `json:"L,omitempty"`
M map[string]int `json:"M,omitempty"`
N map[string]ExternalTestType2 `json:"N,omitempty"`
O *ExternalTestType2 `json:"O,omitempty"`
P []ExternalTestType2 `json:"Q,omitempty"`
}
type ExternalInternalSame struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A TestType2 `json:"A,omitempty"`
}
type UnversionedType struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
}
type UnknownType struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
}
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() schema.ObjectKind { return obj }
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk schema.GroupVersionKind) {
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
}
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() schema.GroupVersionKind {
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
}
func (obj *ExternalInternalSame) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *TestType1) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *ExternalTestType1) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *TestType2) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
func (obj *ExternalTestType2) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}
// TestObjectFuzzer can randomly populate all the above objects.
var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
func(j *MyWeirdCustomEmbeddedVersionKindField, c fuzz.Continue) {
// We have to customize the randomization of MyWeirdCustomEmbeddedVersionKindFields because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = ""
j.ObjectKind = ""
j.ID = c.RandString()
},
)
// Returns a new Scheme set up with the test objects.
func GetTestScheme() *runtime.Scheme {
internalGV := schema.GroupVersion{Version: "__internal"}
externalGV := schema.GroupVersion{Version: "v1"}
alternateExternalGV := schema.GroupVersion{Group: "custom", Version: "v1"}
differentExternalGV := schema.GroupVersion{Group: "other", Version: "v2"}
s := runtime.NewScheme()
// Ordinarily, we wouldn't add TestType2, but because this is a test and
// both types are from the same package, we need to get it into the system
// so that converter will match it with ExternalType2.
s.AddKnownTypes(internalGV, &TestType1{}, &TestType2{}, &ExternalInternalSame{})
s.AddKnownTypes(externalGV, &ExternalInternalSame{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &ExternalTestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &ExternalTestType2{})
s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &TestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &ExternalTestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &ExternalTestType1{})
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &ExternalTestType1{})
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &ExternalTestType1{})
s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &ExternalTestType1{})
s.AddUnversionedTypes(externalGV, &UnversionedType{})
return s
}
func TestKnownTypes(t *testing.T) {
s := GetTestScheme()
if len(s.KnownTypes(schema.GroupVersion{Group: "group", Version: "v2"})) != 0 {
t.Errorf("should have no known types for v2")
}
types := s.KnownTypes(schema.GroupVersion{Version: "v1"})
for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} {
if _, ok := types[s]; !ok {
t.Errorf("missing type %q", s)
}
}
}
func TestConvertToVersionBasic(t *testing.T) {
s := GetTestScheme()
tt := &TestType1{A: "I'm not a pointer object"}
other, err := s.ConvertToVersion(tt, schema.GroupVersion{Version: "v1"})
if err != nil {
t.Fatalf("Failure: %v", err)
}
converted, ok := other.(*ExternalTestType1)
if !ok {
t.Fatalf("Got wrong type: %T", other)
}
if tt.A != converted.A {
t.Fatalf("Failed to convert object correctly: %#v", converted)
}
}
type testGroupVersioner struct {
target schema.GroupVersionKind
ok bool
}
func (m testGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
return m.target, m.ok
}
func TestConvertToVersion(t *testing.T) {
testCases := []struct {
scheme *runtime.Scheme
in runtime.Object
gv runtime.GroupVersioner
same bool
out runtime.Object
errFn func(error) bool
}{
// errors if the type is not registered in the scheme
{
scheme: GetTestScheme(),
in: &UnknownType{},
errFn: func(err error) bool { return err != nil && runtime.IsNotRegisteredError(err) },
},
// errors if the group versioner returns no target
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: testGroupVersioner{},
errFn: func(err error) bool {
return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
},
},
// converts to internal
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: schema.GroupVersion{Version: "__internal"},
out: &TestType1{A: "test"},
},
// prefers the best match
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: schema.GroupVersions{{Version: "__internal"}, {Version: "v1"}},
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// unversioned type returned as-is
{
scheme: GetTestScheme(),
in: &UnversionedType{A: "test"},
gv: schema.GroupVersions{{Version: "v1"}},
same: true,
out: &UnversionedType{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
A: "test",
},
},
// unversioned type returned when not included in the target types
{
scheme: GetTestScheme(),
in: &UnversionedType{A: "test"},
gv: schema.GroupVersions{{Group: "other", Version: "v2"}},
same: true,
out: &UnversionedType{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
A: "test",
},
},
// detected as already being in the target version
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: schema.GroupVersions{{Version: "v1"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// detected as already being in the first target version
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: schema.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// detected as already being in the first target version
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: schema.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (1/3): different kind
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Version: "v1"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
A: "test",
},
},
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (2/3): different gv
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Group: "custom", Version: "v1"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"},
A: "test",
},
},
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (3/3): different gvk
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Group: "custom", Version: "v1", Kind: "TestType5"}},
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
A: "test",
},
},
// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
A: "test",
},
},
// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
A: "test",
},
},
// multi group versioner is unable to find a match when kind AND group don't match (there is no TestType1 kind in group "other", and no kind "TestType5" in the default group)
{
scheme: GetTestScheme(),
in: &TestType1{A: "test"},
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "custom", Version: "v1"}, schema.GroupKind{Group: "other"}, schema.GroupKind{Kind: "TestType5"}),
errFn: func(err error) bool {
return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
},
},
// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
{
scheme: GetTestScheme(),
in: &ExternalTestType1{A: "test"},
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
same: true,
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
A: "test",
},
},
// group versioner can choose a particular target kind for a given input when kind is the same across group versions
{
scheme: GetTestScheme(),
in: &TestType1{A: "test"},
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Version: "v1", Kind: "TestType3"}},
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
A: "test",
},
},
// group versioner can choose a different kind
{
scheme: GetTestScheme(),
in: &TestType1{A: "test"},
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType5", Group: "custom", Version: "v1"}},
out: &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
A: "test",
},
},
}
for i, test := range testCases {
original, _ := test.scheme.DeepCopy(test.in)
out, err := test.scheme.ConvertToVersion(test.in, test.gv)
switch {
case test.errFn != nil:
if !test.errFn(err) {
t.Errorf("%d: unexpected error: %v", i, err)
}
continue
case err != nil:
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if out == test.in {
t.Errorf("%d: ConvertToVersion should always copy out: %#v", i, out)
continue
}
if test.same {
if !reflect.DeepEqual(original, test.in) {
t.Errorf("%d: unexpected mutation of input: %s", i, diff.ObjectReflectDiff(original, test.in))
continue
}
if !reflect.DeepEqual(out, test.out) {
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
continue
}
unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(unsafe, test.out) {
t.Errorf("%d: unexpected unsafe: %s", i, diff.ObjectReflectDiff(unsafe, test.out))
continue
}
if unsafe != test.in {
t.Errorf("%d: UnsafeConvertToVersion should return same object: %#v", i, unsafe)
continue
}
continue
}
if !reflect.DeepEqual(out, test.out) {
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
continue
}
}
}
func TestMetaValues(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: "__internal"}
externalGV := schema.GroupVersion{Group: "test.group", Version: "externalVersion"}
s := runtime.NewScheme()
s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{})
s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{})
internalToExternalCalls := 0
externalToInternalCalls := 0
// Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
t.Logf("internal -> external")
scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++
return nil
},
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
t.Logf("external -> internal")
scope.Convert(&in.TestString, &out.TestString, 0)
externalToInternalCalls++
return nil
},
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
simple := &InternalSimple{
TestString: "foo",
}
s.Log(t)
out, err := s.ConvertToVersion(simple, externalGV)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
internal, err := s.ConvertToVersion(out, internalGV)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := simple, internal; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
if e, a := 1, internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e, a := 1, externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
func TestMetaValuesUnregisteredConvert(t *testing.T) {
type InternalSimple struct {
Version string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"`
TestString string `json:"testString"`
}
type ExternalSimple struct {
Version string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"`
TestString string `json:"testString"`
}
s := runtime.NewScheme()
// We deliberately don't register the types.
internalToExternalCalls := 0
// Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++
return nil
},
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
simple := &InternalSimple{TestString: "foo"}
external := &ExternalSimple{}
err = s.Convert(simple, external, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// Verify that our conversion handler got called.
if e, a := 1, internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}

View file

@ -1,426 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 serializer
import (
"encoding/json"
"fmt"
"log"
"os"
"reflect"
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"github.com/ghodss/yaml"
"github.com/google/gofuzz"
flag "github.com/spf13/pflag"
)
var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
type testMetaFactory struct{}
func (testMetaFactory) Interpret(data []byte) (*schema.GroupVersionKind, error) {
findKind := struct {
APIVersion string `json:"myVersionKey,omitempty"`
ObjectKind string `json:"myKindKey,omitempty"`
}{}
// yaml is a superset of json, so we use it to decode here. That way,
// we understand both.
if err := yaml.Unmarshal(data, &findKind); err != nil {
return nil, fmt.Errorf("couldn't get version/kind: %v", err)
}
gv, err := schema.ParseGroupVersion(findKind.APIVersion)
if err != nil {
return nil, err
}
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: findKind.ObjectKind}, nil
}
// Test a weird version/kind embedding format.
type MyWeirdCustomEmbeddedVersionKindField struct {
ID string `json:"ID,omitempty"`
APIVersion string `json:"myVersionKey,omitempty"`
ObjectKind string `json:"myKindKey,omitempty"`
Z string `json:"Z,omitempty"`
Y uint64 `json:"Y,omitempty"`
}
type TestType1 struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
C int8 `json:"C,omitempty"`
D int16 `json:"D,omitempty"`
E int32 `json:"E,omitempty"`
F int64 `json:"F,omitempty"`
G uint `json:"G,omitempty"`
H uint8 `json:"H,omitempty"`
I uint16 `json:"I,omitempty"`
J uint32 `json:"J,omitempty"`
K uint64 `json:"K,omitempty"`
L bool `json:"L,omitempty"`
M map[string]int `json:"M,omitempty"`
N map[string]TestType2 `json:"N,omitempty"`
O *TestType2 `json:"O,omitempty"`
P []TestType2 `json:"Q,omitempty"`
}
type TestType2 struct {
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
}
type ExternalTestType2 struct {
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
}
type ExternalTestType1 struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A string `json:"A,omitempty"`
B int `json:"B,omitempty"`
C int8 `json:"C,omitempty"`
D int16 `json:"D,omitempty"`
E int32 `json:"E,omitempty"`
F int64 `json:"F,omitempty"`
G uint `json:"G,omitempty"`
H uint8 `json:"H,omitempty"`
I uint16 `json:"I,omitempty"`
J uint32 `json:"J,omitempty"`
K uint64 `json:"K,omitempty"`
L bool `json:"L,omitempty"`
M map[string]int `json:"M,omitempty"`
N map[string]ExternalTestType2 `json:"N,omitempty"`
O *ExternalTestType2 `json:"O,omitempty"`
P []ExternalTestType2 `json:"Q,omitempty"`
}
type ExternalInternalSame struct {
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
A TestType2 `json:"A,omitempty"`
}
// TestObjectFuzzer can randomly populate all the above objects.
var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
func(j *MyWeirdCustomEmbeddedVersionKindField, c fuzz.Continue) {
c.FuzzNoCustom(j)
j.APIVersion = ""
j.ObjectKind = ""
},
)
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() schema.ObjectKind { return obj }
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk schema.GroupVersionKind) {
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
}
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() schema.GroupVersionKind {
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
}
func (obj *ExternalInternalSame) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *TestType1) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *ExternalTestType1) GetObjectKind() schema.ObjectKind {
return &obj.MyWeirdCustomEmbeddedVersionKindField
}
func (obj *TestType2) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
func (obj *ExternalTestType2) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}
// Returns a new Scheme set up with the test objects.
func GetTestScheme() (*runtime.Scheme, runtime.Codec) {
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Version: "v1"}
externalGV2 := schema.GroupVersion{Version: "v2"}
s := runtime.NewScheme()
// Ordinarily, we wouldn't add TestType2, but because this is a test and
// both types are from the same package, we need to get it into the system
// so that converter will match it with ExternalType2.
s.AddKnownTypes(internalGV, &TestType1{}, &TestType2{}, &ExternalInternalSame{})
s.AddKnownTypes(externalGV, &ExternalInternalSame{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &ExternalTestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &ExternalTestType2{})
s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &TestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &ExternalTestType1{})
s.AddKnownTypeWithName(externalGV2.WithKind("TestType1"), &ExternalTestType1{})
s.AddUnversionedTypes(externalGV, &metav1.Status{})
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
codec := cf.LegacyCodec(schema.GroupVersion{Version: "v1"})
return s, codec
}
var semantic = conversion.EqualitiesOrDie(
func(a, b MyWeirdCustomEmbeddedVersionKindField) bool {
a.APIVersion, a.ObjectKind = "", ""
b.APIVersion, b.ObjectKind = "", ""
return a == b
},
)
func runTest(t *testing.T, source interface{}) {
name := reflect.TypeOf(source).Elem().Name()
TestObjectFuzzer.Fuzz(source)
_, codec := GetTestScheme()
data, err := runtime.Encode(codec, source.(runtime.Object))
if err != nil {
t.Errorf("%v: %v (%#v)", name, err, source)
return
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Errorf("%v: %v (%v)", name, err, string(data))
return
}
if !semantic.DeepEqual(source, obj2) {
t.Errorf("1: %v: diff: %v", name, diff.ObjectGoPrintSideBySide(source, obj2))
return
}
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
if err := runtime.DecodeInto(codec, data, obj3.(runtime.Object)); err != nil {
t.Errorf("2: %v: %v", name, err)
return
}
if !semantic.DeepEqual(source, obj3) {
t.Errorf("3: %v: diff: %v", name, diff.ObjectDiff(source, obj3))
return
}
}
func TestTypes(t *testing.T) {
table := []interface{}{
&TestType1{},
&ExternalInternalSame{},
}
for _, item := range table {
// Try a few times, since runTest uses random values.
for i := 0; i < *fuzzIters; i++ {
runTest(t, item)
}
}
}
func TestVersionedEncoding(t *testing.T) {
s, _ := GetTestScheme()
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
encoder := info.Serializer
codec := cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v2"}, nil)
out, err := runtime.Encode(codec, &TestType1{})
if err != nil {
t.Fatal(err)
}
if string(out) != `{"myVersionKey":"v2","myKindKey":"TestType1"}`+"\n" {
t.Fatal(string(out))
}
codec = cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v3"}, nil)
_, err = runtime.Encode(codec, &TestType1{})
if err == nil {
t.Fatal(err)
}
// unversioned encode with no versions is written directly to wire
codec = cf.CodecForVersions(encoder, nil, runtime.InternalGroupVersioner, nil)
out, err = runtime.Encode(codec, &TestType1{})
if err != nil {
t.Fatal(err)
}
if string(out) != `{}`+"\n" {
t.Fatal(string(out))
}
}
func TestMultipleNames(t *testing.T) {
_, codec := GetTestScheme()
obj, _, err := codec.Decode([]byte(`{"myKindKey":"TestType3","myVersionKey":"v1","A":"value"}`), nil, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
internal := obj.(*TestType1)
if internal.A != "value" {
t.Fatalf("unexpected decoded object: %#v", internal)
}
out, err := runtime.Encode(codec, internal)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !strings.Contains(string(out), `"myKindKey":"TestType1"`) {
t.Errorf("unexpected encoded output: %s", string(out))
}
}
func TestConvertTypesWhenDefaultNamesMatch(t *testing.T) {
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Version: "v1"}
s := runtime.NewScheme()
// create two names internally, with TestType1 being preferred
s.AddKnownTypeWithName(internalGV.WithKind("TestType1"), &TestType1{})
s.AddKnownTypeWithName(internalGV.WithKind("OtherType1"), &TestType1{})
// create two names externally, with TestType1 being preferred
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &ExternalTestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("OtherType1"), &ExternalTestType1{})
ext := &ExternalTestType1{}
ext.APIVersion = "v1"
ext.ObjectKind = "OtherType1"
ext.A = "test"
data, err := json.Marshal(ext)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expect := &TestType1{A: "test"}
codec := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})).LegacyCodec(schema.GroupVersion{Version: "v1"})
obj, err := runtime.Decode(codec, data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !semantic.DeepEqual(expect, obj) {
t.Errorf("unexpected object: %#v", obj)
}
into := &TestType1{}
if err := runtime.DecodeInto(codec, data, into); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !semantic.DeepEqual(expect, into) {
t.Errorf("unexpected object: %#v", obj)
}
}
func TestEncode_Ptr(t *testing.T) {
_, codec := GetTestScheme()
tt := &TestType1{A: "I am a pointer object"}
data, err := runtime.Encode(codec, tt)
obj2, err2 := runtime.Decode(codec, data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'\n%s", err, err2, data)
}
if _, ok := obj2.(*TestType1); !ok {
t.Fatalf("Got wrong type")
}
if !semantic.DeepEqual(obj2, tt) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", tt, obj2)
}
}
func TestBadJSONRejection(t *testing.T) {
log.SetOutput(os.Stderr)
_, codec := GetTestScheme()
badJSONs := [][]byte{
[]byte(`{"myVersionKey":"v1"}`), // Missing kind
[]byte(`{"myVersionKey":"v1","myKindKey":"bar"}`), // Unknown kind
[]byte(`{"myVersionKey":"bar","myKindKey":"TestType1"}`), // Unknown version
[]byte(`{"myKindKey":"TestType1"}`), // Missing version
}
for _, b := range badJSONs {
if _, err := runtime.Decode(codec, b); err == nil {
t.Errorf("Did not reject bad json: %s", string(b))
}
}
badJSONKindMismatch := []byte(`{"myVersionKey":"v1","myKindKey":"ExternalInternalSame"}`)
if err := runtime.DecodeInto(codec, badJSONKindMismatch, &TestType1{}); err == nil {
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
}
if err := runtime.DecodeInto(codec, []byte(``), &TestType1{}); err != nil {
t.Errorf("Should allow empty decode: %v", err)
}
if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err == nil {
t.Errorf("Did not give error for empty data with only kind default")
}
if _, _, err := codec.Decode([]byte(`{"myVersionKey":"v1"}`), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err != nil {
t.Errorf("Gave error for version and kind default")
}
if _, _, err := codec.Decode([]byte(`{"myKindKey":"ExternalInternalSame"}`), &schema.GroupVersionKind{Version: "v1"}, nil); err != nil {
t.Errorf("Gave error for version and kind default")
}
if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame", Version: "v1"}, nil); err != nil {
t.Errorf("Gave error for version and kind defaulted: %v", err)
}
if _, err := runtime.Decode(codec, []byte(``)); err == nil {
t.Errorf("Did not give error for empty data")
}
}
// Returns a new Scheme set up with the test objects needed by TestDirectCodec.
func GetDirectCodecTestScheme() *runtime.Scheme {
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
externalGV := schema.GroupVersion{Version: "v1"}
s := runtime.NewScheme()
// Ordinarily, we wouldn't add TestType2, but because this is a test and
// both types are from the same package, we need to get it into the system
// so that converter will match it with ExternalType2.
s.AddKnownTypes(internalGV, &TestType1{})
s.AddKnownTypes(externalGV, &ExternalTestType1{})
s.AddUnversionedTypes(externalGV, &metav1.Status{})
return s
}
func TestDirectCodec(t *testing.T) {
s := GetDirectCodecTestScheme()
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
serializer := info.Serializer
df := DirectCodecFactory{cf}
ignoredGV, err := schema.ParseGroupVersion("ignored group/ignored version")
if err != nil {
t.Fatal(err)
}
directEncoder := df.EncoderForVersion(serializer, ignoredGV)
directDecoder := df.DecoderToVersion(serializer, ignoredGV)
out, err := runtime.Encode(directEncoder, &ExternalTestType1{})
if err != nil {
t.Fatal(err)
}
if string(out) != `{"myVersionKey":"v1","myKindKey":"ExternalTestType1"}`+"\n" {
t.Fatal(string(out))
}
a, _, err := directDecoder.Decode(out, nil, nil)
e := &ExternalTestType1{
MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{
APIVersion: "v1",
ObjectKind: "ExternalTestType1",
},
}
if !semantic.DeepEqual(e, a) {
t.Fatalf("expect %v, got %v", e, a)
}
}

View file

@ -1,264 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/util/diff"
)
type testDecodable struct {
Other string
Value int `json:"value"`
gvk schema.GroupVersionKind
}
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 }
func TestDecode(t *testing.T) {
testCases := []struct {
creater runtime.ObjectCreater
typer runtime.ObjectTyper
yaml bool
pretty bool
data []byte
defaultGVK *schema.GroupVersionKind
into runtime.Object
errFn func(error) bool
expectedObject runtime.Object
expectedGVK *schema.GroupVersionKind
}{
{
data: []byte("{}"),
expectedGVK: &schema.GroupVersionKind{},
errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") },
},
{
data: []byte("{}"),
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{err: fmt.Errorf("fake error")},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
errFn: func(err error) bool { return err.Error() == "fake error" },
},
{
data: []byte("{}"),
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
},
// version without group is not defaulted
{
data: []byte(`{"apiVersion":"blah"}`),
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
},
// group without version is defaulted
{
data: []byte(`{"apiVersion":"other/"}`),
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
},
// accept runtime.Unknown as into and bypass creator
{
data: []byte(`{}`),
into: &runtime.Unknown{},
expectedGVK: &schema.GroupVersionKind{},
expectedObject: &runtime.Unknown{
Raw: []byte(`{}`),
ContentType: runtime.ContentTypeJSON,
},
},
{
data: []byte(`{"test":"object"}`),
into: &runtime.Unknown{},
expectedGVK: &schema.GroupVersionKind{},
expectedObject: &runtime.Unknown{
Raw: []byte(`{"test":"object"}`),
ContentType: runtime.ContentTypeJSON,
},
},
{
data: []byte(`{"test":"object"}`),
into: &runtime.Unknown{},
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
expectedObject: &runtime.Unknown{
TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"},
Raw: []byte(`{"test":"object"}`),
ContentType: runtime.ContentTypeJSON,
},
},
// unregistered objects can be decoded into directly
{
data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`),
into: &testDecodable{},
typer: &mockTyper{err: runtime.NewNotRegisteredErr(schema.GroupVersionKind{}, nil)},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
expectedObject: &testDecodable{
Other: "test",
Value: 1,
},
},
// registered types get defaulted by the into object kind
{
data: []byte(`{"value":1,"Other":"test"}`),
into: &testDecodable{},
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
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{},
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""},
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{}},
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"},
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}}},
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
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) {
t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
}
}
}
type mockCreater struct {
apiVersion string
kind string
err error
obj runtime.Object
}
func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind
return c.obj, c.err
}
type mockTyper struct {
gvk *schema.GroupVersionKind
err error
}
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
if t.gvk == nil {
return nil, false, t.err
}
return []schema.GroupVersionKind{*t.gvk}, false, t.err
}
func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool {
return false
}

View file

@ -1,45 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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
import "testing"
func TestSimpleMetaFactoryInterpret(t *testing.T) {
factory := SimpleMetaFactory{}
gvk, err := factory.Interpret([]byte(`{"apiVersion":"1","kind":"object"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gvk.Version != "1" || gvk.Kind != "object" {
t.Errorf("unexpected interpret: %#v", gvk)
}
// no kind or version
gvk, err = factory.Interpret([]byte(`{}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gvk.Version != "" || gvk.Kind != "" {
t.Errorf("unexpected interpret: %#v", gvk)
}
// unparsable
gvk, err = factory.Interpret([]byte(`{`))
if err == nil {
t.Errorf("unexpected non-error")
}
}

View file

@ -1,58 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 testing
import (
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
)
type A struct{}
func (A) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
func TestRecognizer(t *testing.T) {
s := runtime.NewScheme()
s.AddKnownTypes(schema.GroupVersion{Version: "v1"}, &A{})
d := recognizer.NewDecoder(
json.NewSerializer(json.DefaultMetaFactory, s, s, false),
json.NewYAMLSerializer(json.DefaultMetaFactory, s, s),
)
out, _, err := d.Decode([]byte(`
kind: A
apiVersion: v1
`), nil, nil)
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", out)
out, _, err = d.Decode([]byte(`
{
"kind":"A",
"apiVersion":"v1"
}
`), nil, nil)
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", out)
}

View file

@ -1,84 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
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 streaming
import (
"bytes"
"io"
"io/ioutil"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/framer"
)
type fakeDecoder struct {
got []byte
obj runtime.Object
err error
}
func (d *fakeDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
d.got = data
return d.obj, nil, d.err
}
func TestEmptyDecoder(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
d := &fakeDecoder{}
_, _, err := NewDecoder(ioutil.NopCloser(buf), d).Decode(nil, nil)
if err != io.EOF {
t.Fatal(err)
}
}
func TestDecoder(t *testing.T) {
frames := [][]byte{
make([]byte, 1025),
make([]byte, 1024*5),
make([]byte, 1024*1024*5),
make([]byte, 1025),
}
pr, pw := io.Pipe()
fw := framer.NewLengthDelimitedFrameWriter(pw)
go func() {
for i := range frames {
fw.Write(frames[i])
}
pw.Close()
}()
r := framer.NewLengthDelimitedFrameReader(pr)
d := &fakeDecoder{}
dec := NewDecoder(r, d)
if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[0]) {
t.Fatalf("unexpected %v %v", err, len(d.got))
}
if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[1]) {
t.Fatalf("unexpected %v %v", err, len(d.got))
}
if _, _, err := dec.Decode(nil, nil); err != ErrObjectTooLarge || !bytes.Equal(d.got, frames[1]) {
t.Fatalf("unexpected %v %v", err, len(d.got))
}
if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[3]) {
t.Fatalf("unexpected %v %v", err, len(d.got))
}
if _, _, err := dec.Decode(nil, nil); err != io.EOF {
t.Fatalf("unexpected %v %v", err, len(d.got))
}
}

View file

@ -1,399 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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"
"io/ioutil"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
)
type testDecodable struct {
Other string
Value int `json:"value"`
gvk schema.GroupVersionKind
}
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 }
type testNestedDecodable struct {
Other string
Value int `json:"value"`
gvk schema.GroupVersionKind
nestedCalled bool
nestedErr error
}
func (d *testNestedDecodable) GetObjectKind() schema.ObjectKind { return d }
func (d *testNestedDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
func (d *testNestedDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error {
d.nestedCalled = true
return d.nestedErr
}
func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
d.nestedCalled = true
return d.nestedErr
}
func TestNestedDecode(t *testing.T) {
n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
decoder := &mockSerializer{obj: n}
codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil, nil)
if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr {
t.Errorf("unexpected error: %v", err)
}
if !n.nestedCalled {
t.Errorf("did not invoke nested decoder")
}
}
func TestNestedEncode(t *testing.T) {
n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
n2 := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode 2")}
encoder := &mockSerializer{obj: n}
codec := NewCodec(
encoder, nil,
&checkConvertor{obj: n2, groupVersion: schema.GroupVersion{Group: "other"}},
nil, nil,
&mockTyper{gvks: []schema.GroupVersionKind{{Kind: "test"}}},
nil,
schema.GroupVersion{Group: "other"}, nil,
)
if err := codec.Encode(n, ioutil.Discard); err != n2.nestedErr {
t.Errorf("unexpected error: %v", err)
}
if n.nestedCalled || !n2.nestedCalled {
t.Errorf("did not invoke correct nested decoder")
}
}
func TestDecode(t *testing.T) {
gvk1 := &schema.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.ObjectTyper
defaulter runtime.ObjectDefaulter
yaml bool
pretty bool
encodes, decodes runtime.GroupVersioner
defaultGVK *schema.GroupVersionKind
into runtime.Object
errFn func(error) bool
expectedObject runtime.Object
sameObject runtime.Object
expectedGVK *schema.GroupVersionKind
}{
{
serializer: &mockSerializer{actual: gvk1},
convertor: &checkConvertor{groupVersion: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
decodes: schema.GroupVersion{Group: "other", Version: "__internal"},
},
{
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
sameObject: decodable2,
decodes: schema.GroupVersion{Group: "other", Version: "__internal"},
},
// defaultGVK.Group is allowed to force a conversion to the destination group
{
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
defaultGVK: &schema.GroupVersionKind{Group: "force"},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "force", Version: "__internal"}},
expectedGVK: gvk1,
sameObject: decodable2,
decodes: schema.GroupVersion{Group: "force", Version: "__internal"},
},
// 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: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
decodes: schema.GroupVersion{Group: "other", Version: "__internal"},
},
{
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: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
decodes: schema.GroupVersion{Group: "other", Version: "__internal"},
},
// decode into the same version as the serialized object
{
decodes: schema.GroupVersions{gvk1.GroupVersion()},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}},
expectedGVK: gvk1,
expectedObject: decodable1,
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
decodes: schema.GroupVersions{gvk1.GroupVersion()},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}},
copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
},
// codec with non matching version skips conversion altogether
{
decodes: schema.GroupVersions{{Group: "something", Version: "else"}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "something", Version: "else"}}},
expectedGVK: gvk1,
expectedObject: decodable1,
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
decodes: schema.GroupVersions{{Group: "something", Version: "else"}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "something", Version: "else"}}},
copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
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.defaulter, 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 runtime.GroupVersioner
directConvert bool
}
func (c *checkConvertor) Convert(in, out, context 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 runtime.GroupVersioner) (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 !reflect.DeepEqual(c.groupVersion, outVersion) {
return nil, fmt.Errorf("unexpected outversion: %s (%s)", outVersion, c.groupVersion)
}
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
encodingObjGVK schema.GroupVersionKind
defaults, actual *schema.GroupVersionKind
into runtime.Object
}
func (s *mockSerializer) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
s.defaults = defaults
s.into = into
return s.obj, s.actual, s.err
}
func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error {
s.obj = obj
s.encodingObjGVK = obj.GetObjectKind().GroupVersionKind()
return s.err
}
type mockCreater struct {
err error
obj runtime.Object
}
func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
return c.obj, c.err
}
type mockTyper struct {
gvks []schema.GroupVersionKind
unversioned bool
err error
}
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
return t.gvks, t.unversioned, t.err
}
func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool {
return true
}
func TestDirectCodecEncode(t *testing.T) {
serializer := mockSerializer{}
typer := mockTyper{
gvks: []schema.GroupVersionKind{
{
Group: "wrong_group",
Kind: "some_kind",
},
{
Group: "expected_group",
Kind: "some_kind",
},
},
}
c := DirectEncoder{
Version: schema.GroupVersion{Group: "expected_group"},
Encoder: &serializer,
ObjectTyper: &typer,
}
c.Encode(&testDecodable{}, ioutil.Discard)
if e, a := "expected_group", serializer.encodingObjGVK.Group; e != a {
t.Errorf("expected group to be %v, got %v", e, a)
}
}

View file

@ -1,46 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors.
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 yaml
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/yaml"
)
// yamlSerializer converts YAML passed to the Decoder methods to JSON.
type yamlSerializer struct {
// the nested serializer
runtime.Serializer
}
// yamlSerializer implements Serializer
var _ runtime.Serializer = yamlSerializer{}
// NewDecodingSerializer adds YAML decoding support to a serializer that supports JSON.
func NewDecodingSerializer(jsonSerializer runtime.Serializer) runtime.Serializer {
return &yamlSerializer{jsonSerializer}
}
func (c yamlSerializer) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
out, err := yaml.ToJSON(data)
if err != nil {
return nil, nil, err
}
data = out
return c.Serializer.Decode(data, gvk, into)
}

View file

@ -1,43 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
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 runtime
import (
"testing"
)
func TestFmtRawDoc(t *testing.T) {
tests := []struct {
t, expected string
}{
{"aaa\n --- asd\n TODO: tooooodo\n toooodoooooo\n", "aaa"},
{"aaa\nasd\n TODO: tooooodo\nbbbb\n --- toooodoooooo\n", "aaa asd bbbb"},
{" TODO: tooooodo\n", ""},
{"Par1\n\nPar2\n\n", "Par1\\n\\nPar2"},
{"", ""},
{" ", ""},
{" \n", ""},
{" \n\n ", ""},
{"Example:\n\tl1\n\t\tl2\n", "Example:\\n\\tl1\\n\\t\\tl2"},
}
for _, test := range tests {
if o := fmtRawDoc(test.t); o != test.expected {
t.Fatalf("Expected: %q, got %q", test.expected, o)
}
}
}