2014-09-11 00:28:07 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-09-11 00:28:07 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package runtime_test
import (
"reflect"
2016-05-22 23:10:42 +00:00
"strings"
2014-09-11 00:28:07 +00:00
"testing"
2016-01-25 23:47:26 +00:00
"github.com/google/gofuzz"
flag "github.com/spf13/pflag"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
2016-11-21 02:55:31 +00:00
"k8s.io/kubernetes/pkg/runtime/schema"
2015-12-21 05:08:33 +00:00
"k8s.io/kubernetes/pkg/runtime/serializer"
2016-03-11 02:43:55 +00:00
"k8s.io/kubernetes/pkg/util/diff"
2014-09-11 00:28:07 +00:00
)
2016-01-25 23:47:26 +00:00
var fuzzIters = flag . Int ( "fuzz-iters" , 50 , "How many fuzzing iterations to do." )
2015-12-08 03:01:12 +00:00
2014-09-11 00:28:07 +00:00
type InternalSimple struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
TestString string ` json:"testString" `
2014-09-11 00:28:07 +00:00
}
type ExternalSimple struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
TestString string ` json:"testString" `
2014-09-11 00:28:07 +00:00
}
2016-11-21 02:55:31 +00:00
func ( obj * InternalSimple ) GetObjectKind ( ) schema . ObjectKind { return & obj . TypeMeta }
func ( obj * ExternalSimple ) GetObjectKind ( ) schema . ObjectKind { return & obj . TypeMeta }
2014-09-11 00:28:07 +00:00
func TestScheme ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : runtime . APIVersionInternal }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "testExternal" }
2015-11-17 15:07:45 +00:00
2014-09-11 17:02:53 +00:00
scheme := runtime . NewScheme ( )
2015-11-18 15:34:16 +00:00
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "Simple" ) , & InternalSimple { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "Simple" ) , & ExternalSimple { } )
2014-09-11 00:28:07 +00:00
2015-12-21 05:08:33 +00:00
// If set, would clear TypeMeta during conversion.
//scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{})
2014-10-29 16:10:55 +00:00
// test that scheme is an ObjectTyper
var _ runtime . ObjectTyper = scheme
2014-09-11 00:28:07 +00:00
internalToExternalCalls := 0
externalToInternalCalls := 0
// Register functions to verify that scope.Meta() gets set correctly.
2014-09-11 17:02:53 +00:00
err := scheme . AddConversionFuncs (
2014-09-11 00:28:07 +00:00
func ( in * InternalSimple , out * ExternalSimple , scope conversion . Scope ) error {
2014-10-07 15:12:16 +00:00
scope . Convert ( & in . TypeMeta , & out . TypeMeta , 0 )
2014-09-11 00:28:07 +00:00
scope . Convert ( & in . TestString , & out . TestString , 0 )
internalToExternalCalls ++
return nil
} ,
func ( in * ExternalSimple , out * InternalSimple , scope conversion . Scope ) error {
2014-10-07 15:12:16 +00:00
scope . Convert ( & in . TypeMeta , & out . TypeMeta , 0 )
2014-09-11 00:28:07 +00:00
scope . Convert ( & in . TestString , & out . TestString , 0 )
externalToInternalCalls ++
return nil
} ,
)
if err != nil {
2015-12-21 05:08:33 +00:00
t . Fatalf ( "unexpected error: %v" , err )
2014-09-11 00:28:07 +00:00
}
2015-12-21 05:08:33 +00:00
codecs := serializer . NewCodecFactory ( scheme )
codec := codecs . LegacyCodec ( externalGV )
2016-10-12 20:55:28 +00:00
info , _ := runtime . SerializerInfoForMediaType ( codecs . SupportedMediaTypes ( ) , runtime . ContentTypeJSON )
jsonserializer := info . Serializer
2015-12-21 05:08:33 +00:00
2014-09-11 00:28:07 +00:00
simple := & InternalSimple {
TestString : "foo" ,
}
2015-08-07 19:45:20 +00:00
// Test Encode, Decode, DecodeInto, and DecodeToVersion
2014-09-11 00:28:07 +00:00
obj := runtime . Object ( simple )
2015-12-21 05:08:33 +00:00
data , err := runtime . Encode ( codec , obj )
if err != nil {
t . Fatal ( err )
}
obj2 , err := runtime . Decode ( codec , data )
if err != nil {
t . Fatal ( err )
2014-09-11 00:28:07 +00:00
}
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 )
}
2015-12-21 05:08:33 +00:00
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).
2016-01-25 23:47:26 +00:00
simple . TypeMeta = runtime . TypeMeta { Kind : "Simple" , APIVersion : externalGV . String ( ) }
2014-09-11 00:28:07 +00:00
if e , a := simple , obj3 ; ! reflect . DeepEqual ( e , a ) {
t . Errorf ( "Expected:\n %#v,\n Got:\n %#v" , e , a )
}
2015-12-21 05:08:33 +00:00
obj4 , err := runtime . Decode ( jsonserializer , data )
if err != nil {
t . Fatal ( err )
}
2015-08-07 19:45:20 +00:00
if _ , ok := obj4 . ( * ExternalSimple ) ; ! ok {
t . Fatalf ( "Got wrong type" )
}
2014-09-11 00:28:07 +00:00
// Test Convert
external := & ExternalSimple { }
2016-07-04 20:13:27 +00:00
err = scheme . Convert ( simple , external , nil )
2014-09-11 00:28:07 +00:00
if err != nil {
2015-12-21 05:08:33 +00:00
t . Fatalf ( "Unexpected error: %v" , err )
2014-09-11 00:28:07 +00:00
}
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 )
}
2015-12-21 05:08:33 +00:00
// DecodeInto and Decode should each have caused an increment because of a conversion
2014-09-11 00:28:07 +00:00
if e , a := 2 , externalToInternalCalls ; e != a {
t . Errorf ( "Expected %v, got %v" , e , a )
}
}
func TestBadJSONRejection ( t * testing . T ) {
2014-09-11 17:02:53 +00:00
scheme := runtime . NewScheme ( )
2015-12-21 05:08:33 +00:00
codecs := serializer . NewCodecFactory ( scheme )
2016-10-12 20:55:28 +00:00
info , _ := runtime . SerializerInfoForMediaType ( codecs . SupportedMediaTypes ( ) , runtime . ContentTypeJSON )
jsonserializer := info . Serializer
2015-12-21 05:08:33 +00:00
2014-09-11 00:28:07 +00:00
badJSONMissingKind := [ ] byte ( ` { } ` )
2015-12-21 05:08:33 +00:00
if _ , err := runtime . Decode ( jsonserializer , badJSONMissingKind ) ; err == nil {
2014-09-11 00:28:07 +00:00
t . Errorf ( "Did not reject despite lack of kind field: %s" , badJSONMissingKind )
}
badJSONUnknownType := [ ] byte ( ` { "kind": "bar"} ` )
2015-12-21 05:08:33 +00:00
if _ , err1 := runtime . Decode ( jsonserializer , badJSONUnknownType ) ; err1 == nil {
2014-09-11 00:28:07 +00:00
t . Errorf ( "Did not reject despite use of unknown type: %s" , badJSONUnknownType )
}
/ * badJSONKindMismatch := [ ] byte ( ` { "kind": "Pod"} ` )
2016-05-05 20:41:49 +00:00
if err2 := DecodeInto ( badJSONKindMismatch , & Node { } ) ; err2 == nil {
2014-09-11 00:28:07 +00:00
t . Errorf ( "Kind is set but doesn't match the object type: %s" , badJSONKindMismatch )
} * /
}
type ExtensionA struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
TestString string ` json:"testString" `
2014-09-11 00:28:07 +00:00
}
type ExtensionB struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
TestString string ` json:"testString" `
2014-09-11 00:28:07 +00:00
}
type ExternalExtensionType struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
Extension runtime . RawExtension ` json:"extension" `
2014-09-11 00:28:07 +00:00
}
type InternalExtensionType struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
Extension runtime . Object ` json:"extension" `
2014-09-11 00:28:07 +00:00
}
2015-02-02 19:21:50 +00:00
type ExternalOptionalExtensionType struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
Extension runtime . RawExtension ` json:"extension,omitempty" `
2015-02-02 19:21:50 +00:00
}
type InternalOptionalExtensionType struct {
2016-01-25 23:47:26 +00:00
runtime . TypeMeta ` json:",inline" `
Extension runtime . Object ` json:"extension,omitempty" `
2015-02-02 19:21:50 +00:00
}
2016-11-21 02:55:31 +00:00
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 }
2015-02-02 19:21:50 +00:00
func TestExternalToInternalMapping ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : runtime . APIVersionInternal }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "testExternal" }
2015-11-17 18:21:32 +00:00
2015-02-02 19:21:50 +00:00
scheme := runtime . NewScheme ( )
2015-11-18 15:34:16 +00:00
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "OptionalExtensionType" ) , & InternalOptionalExtensionType { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "OptionalExtensionType" ) , & ExternalOptionalExtensionType { } )
2015-02-02 19:21:50 +00:00
2015-12-21 05:08:33 +00:00
codec := serializer . NewCodecFactory ( scheme ) . LegacyCodec ( externalGV )
2015-02-02 19:21:50 +00:00
table := [ ] struct {
obj runtime . Object
encoded string
} {
{
2015-12-21 05:08:33 +00:00
& InternalOptionalExtensionType { Extension : nil } ,
2015-11-17 18:21:32 +00:00
` { "kind":"OptionalExtensionType","apiVersion":" ` + externalGV . String ( ) + ` "} ` ,
2015-02-02 19:21:50 +00:00
} ,
}
2015-12-21 05:08:33 +00:00
for i , item := range table {
gotDecoded , err := runtime . Decode ( codec , [ ] byte ( item . encoded ) )
2015-02-02 19:21:50 +00:00
if err != nil {
t . Errorf ( "unexpected error '%v' (%v)" , err , item . encoded )
} else if e , a := item . obj , gotDecoded ; ! reflect . DeepEqual ( e , a ) {
2016-03-11 02:43:55 +00:00
t . Errorf ( "%d: unexpected objects:\n%s" , i , diff . ObjectGoPrintSideBySide ( e , a ) )
2015-02-02 19:21:50 +00:00
}
}
}
2014-09-11 00:28:07 +00:00
2014-09-15 20:11:37 +00:00
func TestExtensionMapping ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : runtime . APIVersionInternal }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "testExternal" }
2015-11-17 18:21:32 +00:00
2014-09-11 17:02:53 +00:00
scheme := runtime . NewScheme ( )
2015-11-18 15:34:16 +00:00
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "ExtensionType" ) , & InternalExtensionType { } )
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "OptionalExtensionType" ) , & InternalOptionalExtensionType { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "ExtensionType" ) , & ExternalExtensionType { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "OptionalExtensionType" ) , & ExternalOptionalExtensionType { } )
2015-12-21 05:08:33 +00:00
// register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the
// external version.
2015-11-18 15:34:16 +00:00
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "A" ) , & ExtensionA { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "B" ) , & ExtensionB { } )
2015-12-21 05:08:33 +00:00
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "A" ) , & ExtensionA { } )
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "B" ) , & ExtensionB { } )
codec := serializer . NewCodecFactory ( scheme ) . LegacyCodec ( externalGV )
2014-09-11 00:28:07 +00:00
table := [ ] struct {
2015-12-21 05:08:33 +00:00
obj runtime . Object
expected runtime . Object
encoded string
2014-09-11 00:28:07 +00:00
} {
{
2015-12-21 05:08:33 +00:00
& InternalExtensionType {
Extension : runtime . NewEncodable ( codec , & ExtensionA { TestString : "foo" } ) ,
} ,
& InternalExtensionType {
Extension : & runtime . Unknown {
2016-03-16 08:03:33 +00:00
Raw : [ ] byte ( ` { "apiVersion":"test.group/testExternal","kind":"A","testString":"foo"} ` ) ,
ContentType : runtime . ContentTypeJSON ,
2015-12-21 05:08:33 +00:00
} ,
} ,
// apiVersion is set in the serialized object for easier consumption by clients
2016-01-25 23:47:26 +00:00
` { "apiVersion":" ` + externalGV . String ( ) + ` "," kind ":" ExtensionType "," extension ":{" apiVersion ":" test . group / testExternal "," kind ":" A "," testString ":" foo " } }
2015-09-18 00:43:05 +00:00
` ,
2014-09-11 00:28:07 +00:00
} , {
2015-12-21 05:08:33 +00:00
& InternalExtensionType { Extension : runtime . NewEncodable ( codec , & ExtensionB { TestString : "bar" } ) } ,
& InternalExtensionType {
Extension : & runtime . Unknown {
2016-03-16 08:03:33 +00:00
Raw : [ ] byte ( ` { "apiVersion":"test.group/testExternal","kind":"B","testString":"bar"} ` ) ,
ContentType : runtime . ContentTypeJSON ,
2015-12-21 05:08:33 +00:00
} ,
} ,
// apiVersion is set in the serialized object for easier consumption by clients
2016-01-25 23:47:26 +00:00
` { "apiVersion":" ` + externalGV . String ( ) + ` "," kind ":" ExtensionType "," extension ":{" apiVersion ":" test . group / testExternal "," kind ":" B "," testString ":" bar " } }
2015-09-18 00:43:05 +00:00
` ,
2014-09-11 00:28:07 +00:00
} , {
2015-12-21 05:08:33 +00:00
& InternalExtensionType { Extension : nil } ,
& InternalExtensionType {
Extension : nil ,
} ,
2016-01-25 23:47:26 +00:00
` { "apiVersion":" ` + externalGV . String ( ) + ` "," kind ":" ExtensionType "," extension " : null }
2015-09-18 00:43:05 +00:00
` ,
2014-09-11 00:28:07 +00:00
} ,
}
2015-12-21 05:08:33 +00:00
for i , item := range table {
gotEncoded , err := runtime . Encode ( codec , item . obj )
2014-09-11 00:28:07 +00:00
if err != nil {
t . Errorf ( "unexpected error '%v' (%#v)" , err , item . obj )
} else if e , a := item . encoded , string ( gotEncoded ) ; e != a {
2015-09-18 00:43:05 +00:00
t . Errorf ( "expected\n%#v\ngot\n%#v\n" , e , a )
2014-09-11 00:28:07 +00:00
}
2015-12-21 05:08:33 +00:00
gotDecoded , err := runtime . Decode ( codec , [ ] byte ( item . encoded ) )
2014-09-11 00:28:07 +00:00
if err != nil {
t . Errorf ( "unexpected error '%v' (%v)" , err , item . encoded )
2015-12-21 05:08:33 +00:00
} else if e , a := item . expected , gotDecoded ; ! reflect . DeepEqual ( e , a ) {
2016-03-11 02:43:55 +00:00
t . Errorf ( "%d: unexpected objects:\n%s" , i , diff . ObjectGoPrintSideBySide ( e , a ) )
2014-09-11 00:28:07 +00:00
}
}
}
2014-09-11 17:02:53 +00:00
func TestEncode ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : runtime . APIVersionInternal }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "testExternal" }
2015-11-17 18:21:32 +00:00
2014-09-11 17:02:53 +00:00
scheme := runtime . NewScheme ( )
2015-11-18 15:34:16 +00:00
scheme . AddKnownTypeWithName ( internalGV . WithKind ( "Simple" ) , & InternalSimple { } )
scheme . AddKnownTypeWithName ( externalGV . WithKind ( "Simple" ) , & ExternalSimple { } )
2015-12-21 05:08:33 +00:00
codec := serializer . NewCodecFactory ( scheme ) . LegacyCodec ( externalGV )
2014-09-11 17:02:53 +00:00
test := & InternalSimple {
TestString : "I'm the same" ,
}
obj := runtime . Object ( test )
2015-12-10 02:15:02 +00:00
data , err := runtime . Encode ( codec , obj )
2015-12-21 05:08:33 +00:00
obj2 , gvk , err2 := codec . Decode ( data , nil , nil )
2014-09-11 17:02:53 +00:00
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 ) {
2015-12-21 05:08:33 +00:00
t . Errorf ( "Expected:\n %#v,\n Got:\n %#v" , test , obj2 )
}
2016-11-21 02:55:31 +00:00
if ! reflect . DeepEqual ( gvk , & schema . GroupVersionKind { Group : "test.group" , Version : "testExternal" , Kind : "Simple" } ) {
2015-12-21 05:08:33 +00:00
t . Errorf ( "unexpected gvk returned by decode: %#v" , gvk )
}
}
func TestUnversionedTypes ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : runtime . APIVersionInternal }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "testExternal" }
otherGV := schema . GroupVersion { Group : "group" , Version : "other" }
2015-12-21 05:08:33 +00:00
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 {
2016-03-23 00:26:50 +00:00
t . Fatalf ( "type not unversioned and in scheme: %t %t" , unv , ok )
2015-12-21 05:08:33 +00:00
}
2016-05-21 04:15:31 +00:00
kinds , _ , err := scheme . ObjectKinds ( & InternalSimple { } )
2015-12-21 05:08:33 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-21 04:15:31 +00:00
kind := kinds [ 0 ]
2015-12-21 05:08:33 +00:00
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)
2016-11-21 02:55:31 +00:00
if ! reflect . DeepEqual ( gvk , & schema . GroupVersionKind { Group : "test.group" , Version : "testExternal" , Kind : "InternalSimple" } ) {
2015-12-21 05:08:33 +00:00
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 )
}
2016-01-25 23:47:26 +00:00
if string ( data ) != ` { "apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"} ` + "\n" {
2015-12-21 05:08:33 +00:00
t . Errorf ( "unexpected data: %s" , data )
2014-09-11 17:02:53 +00:00
}
}
2016-01-25 23:47:26 +00:00
// 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" `
}
2016-05-22 23:10:42 +00:00
type UnversionedType struct {
MyWeirdCustomEmbeddedVersionKindField ` json:",inline" `
A string ` json:"A,omitempty" `
}
type UnknownType struct {
MyWeirdCustomEmbeddedVersionKindField ` json:",inline" `
A string ` json:"A,omitempty" `
}
2016-11-21 02:55:31 +00:00
func ( obj * MyWeirdCustomEmbeddedVersionKindField ) GetObjectKind ( ) schema . ObjectKind { return obj }
func ( obj * MyWeirdCustomEmbeddedVersionKindField ) SetGroupVersionKind ( gvk schema . GroupVersionKind ) {
2016-01-25 23:47:26 +00:00
obj . APIVersion , obj . ObjectKind = gvk . ToAPIVersionAndKind ( )
}
2016-11-21 02:55:31 +00:00
func ( obj * MyWeirdCustomEmbeddedVersionKindField ) GroupVersionKind ( ) schema . GroupVersionKind {
return schema . FromAPIVersionAndKind ( obj . APIVersion , obj . ObjectKind )
2016-01-25 23:47:26 +00:00
}
2016-11-21 02:55:31 +00:00
func ( obj * ExternalInternalSame ) GetObjectKind ( ) schema . ObjectKind {
2016-01-25 23:47:26 +00:00
return & obj . MyWeirdCustomEmbeddedVersionKindField
}
2016-11-21 02:55:31 +00:00
func ( obj * TestType1 ) GetObjectKind ( ) schema . ObjectKind {
2016-01-25 23:47:26 +00:00
return & obj . MyWeirdCustomEmbeddedVersionKindField
}
2016-11-21 02:55:31 +00:00
func ( obj * ExternalTestType1 ) GetObjectKind ( ) schema . ObjectKind {
2016-01-25 23:47:26 +00:00
return & obj . MyWeirdCustomEmbeddedVersionKindField
}
2016-11-21 02:55:31 +00:00
func ( obj * TestType2 ) GetObjectKind ( ) schema . ObjectKind { return schema . EmptyObjectKind }
func ( obj * ExternalTestType2 ) GetObjectKind ( ) schema . ObjectKind {
return schema . EmptyObjectKind
2016-01-25 23:47:26 +00:00
}
// 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 {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Version : "__internal" }
externalGV := schema . GroupVersion { Version : "v1" }
alternateExternalGV := schema . GroupVersion { Group : "custom" , Version : "v1" }
differentExternalGV := schema . GroupVersion { Group : "other" , Version : "v2" }
2016-01-25 23:47:26 +00:00
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 { } )
2016-05-22 23:10:42 +00:00
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 { } )
2016-01-25 23:47:26 +00:00
return s
}
func TestKnownTypes ( t * testing . T ) {
s := GetTestScheme ( )
2016-11-21 02:55:31 +00:00
if len ( s . KnownTypes ( schema . GroupVersion { Group : "group" , Version : "v2" } ) ) != 0 {
2016-01-25 23:47:26 +00:00
t . Errorf ( "should have no known types for v2" )
}
2016-11-21 02:55:31 +00:00
types := s . KnownTypes ( schema . GroupVersion { Version : "v1" } )
2016-01-25 23:47:26 +00:00
for _ , s := range [ ] string { "TestType1" , "TestType2" , "TestType3" , "ExternalInternalSame" } {
if _ , ok := types [ s ] ; ! ok {
t . Errorf ( "missing type %q" , s )
}
}
}
2016-05-22 23:10:42 +00:00
func TestConvertToVersionBasic ( t * testing . T ) {
2016-01-25 23:47:26 +00:00
s := GetTestScheme ( )
tt := & TestType1 { A : "I'm not a pointer object" }
2016-11-21 02:55:31 +00:00
other , err := s . ConvertToVersion ( tt , schema . GroupVersion { Version : "v1" } )
2016-01-25 23:47:26 +00:00
if err != nil {
t . Fatalf ( "Failure: %v" , err )
}
converted , ok := other . ( * ExternalTestType1 )
if ! ok {
2016-05-22 23:10:42 +00:00
t . Fatalf ( "Got wrong type: %T" , other )
2016-01-25 23:47:26 +00:00
}
if tt . A != converted . A {
t . Fatalf ( "Failed to convert object correctly: %#v" , converted )
}
}
2016-05-22 23:10:42 +00:00
type testGroupVersioner struct {
2016-11-21 02:55:31 +00:00
target schema . GroupVersionKind
2016-05-22 23:10:42 +00:00
ok bool
}
2016-11-21 02:55:31 +00:00
func ( m testGroupVersioner ) KindForGroupVersionKinds ( kinds [ ] schema . GroupVersionKind ) ( schema . GroupVersionKind , bool ) {
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersion { Version : "__internal" } ,
2016-05-22 23:10:42 +00:00
out : & TestType1 { A : "test" } ,
} ,
2016-10-04 12:00:47 +00:00
// prefers the best match
2016-05-22 23:10:42 +00:00
{
scheme : GetTestScheme ( ) ,
in : & ExternalTestType1 { A : "test" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Version : "__internal" } , { Version : "v1" } } ,
2016-10-04 12:00:47 +00:00
out : & ExternalTestType1 {
MyWeirdCustomEmbeddedVersionKindField : MyWeirdCustomEmbeddedVersionKindField { APIVersion : "v1" , ObjectKind : "TestType1" } ,
A : "test" ,
} ,
2016-05-22 23:10:42 +00:00
} ,
// unversioned type returned as-is
{
scheme : GetTestScheme ( ) ,
in : & UnversionedType { A : "test" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Version : "v1" } } ,
2016-05-22 23:10:42 +00:00
same : true ,
out : & UnversionedType {
MyWeirdCustomEmbeddedVersionKindField : MyWeirdCustomEmbeddedVersionKindField { APIVersion : "v1" , ObjectKind : "UnversionedType" } ,
A : "test" ,
} ,
} ,
2016-11-02 01:37:13 +00:00
// unversioned type returned when not included in the target types
{
scheme : GetTestScheme ( ) ,
in : & UnversionedType { A : "test" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Group : "other" , Version : "v2" } } ,
2016-11-02 01:37:13 +00:00
same : true ,
out : & UnversionedType {
MyWeirdCustomEmbeddedVersionKindField : MyWeirdCustomEmbeddedVersionKindField { APIVersion : "v1" , ObjectKind : "UnversionedType" } ,
A : "test" ,
} ,
} ,
2016-05-22 23:10:42 +00:00
// detected as already being in the target version
{
scheme : GetTestScheme ( ) ,
in : & ExternalTestType1 { A : "test" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Version : "v1" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Version : "v1" } , { Version : "__internal" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : schema . GroupVersions { { Version : "v1" } , { Version : "__internal" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : testGroupVersioner { ok : true , target : schema . GroupVersionKind { Kind : "TestType3" , Version : "v1" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : testGroupVersioner { ok : true , target : schema . GroupVersionKind { Kind : "TestType3" , Group : "custom" , Version : "v1" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : testGroupVersioner { ok : true , target : schema . GroupVersionKind { Group : "custom" , Version : "v1" , Kind : "TestType5" } } ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : runtime . NewMultiGroupVersioner ( schema . GroupVersion { Group : "other" , Version : "v2" } , schema . GroupKind { Group : "custom" , Kind : "TestType3" } , schema . GroupKind { Kind : "TestType1" } ) ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : runtime . NewMultiGroupVersioner ( schema . GroupVersion { Group : "other" , Version : "v2" } , schema . GroupKind { Kind : "TestType1" } , schema . GroupKind { Group : "custom" , Kind : "TestType3" } ) ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : runtime . NewMultiGroupVersioner ( schema . GroupVersion { Group : "custom" , Version : "v1" } , schema . GroupKind { Group : "other" } , schema . GroupKind { Kind : "TestType5" } ) ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : runtime . NewMultiGroupVersioner ( schema . GroupVersion { Group : "" , Version : "v1" } , schema . GroupKind { Group : "custom" , Kind : "TestType3" } , schema . GroupKind { Kind : "TestType1" } ) ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : runtime . NewMultiGroupVersioner ( schema . GroupVersion { Group : "" , Version : "v1" } , schema . GroupKind { Kind : "TestType1" } , schema . GroupKind { Group : "custom" , Kind : "TestType3" } ) ,
2016-05-22 23:10:42 +00:00
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" } ,
2016-11-21 02:55:31 +00:00
gv : testGroupVersioner { ok : true , target : schema . GroupVersionKind { Version : "v1" , Kind : "TestType3" } } ,
2016-05-22 23:10:42 +00:00
out : & ExternalTestType1 {
MyWeirdCustomEmbeddedVersionKindField : MyWeirdCustomEmbeddedVersionKindField { APIVersion : "v1" , ObjectKind : "TestType3" } ,
A : "test" ,
} ,
} ,
// group versioner can choose a different kind
{
scheme : GetTestScheme ( ) ,
in : & TestType1 { A : "test" } ,
2016-11-21 02:55:31 +00:00
gv : testGroupVersioner { ok : true , target : schema . GroupVersionKind { Kind : "TestType5" , Group : "custom" , Version : "v1" } } ,
2016-05-22 23:10:42 +00:00
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
}
}
}
2016-01-25 23:47:26 +00:00
func TestMetaValues ( t * testing . T ) {
2016-11-21 02:55:31 +00:00
internalGV := schema . GroupVersion { Group : "test.group" , Version : "__internal" }
externalGV := schema . GroupVersion { Group : "test.group" , Version : "externalVersion" }
2016-01-25 23:47:26 +00:00
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 )
2016-05-01 00:43:30 +00:00
out , err := s . ConvertToVersion ( simple , externalGV )
2016-01-25 23:47:26 +00:00
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
2016-05-01 00:43:30 +00:00
internal , err := s . ConvertToVersion ( out , internalGV )
2016-01-25 23:47:26 +00:00
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 { }
2016-07-04 20:13:27 +00:00
err = s . Convert ( simple , external , nil )
2016-01-25 23:47:26 +00:00
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 )
}
}