Merge pull request #85891 from wojtek-t/remove_old_conversions

Remove old-style conversions registration
This commit is contained in:
Kubernetes Prow Robot 2019-12-15 17:59:37 -08:00 committed by GitHub
commit 0a61fd987e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 293 additions and 404 deletions

View File

@ -47,19 +47,6 @@ func addToGroupVersion(scheme *runtime.Scheme) error {
if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil { if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil {
return err return err
} }
err := scheme.AddConversionFuncs(
metav1.Convert_string_To_labels_Selector,
metav1.Convert_labels_Selector_To_string,
metav1.Convert_string_To_fields_Selector,
metav1.Convert_fields_Selector_To_string,
metav1.Convert_Map_string_To_string_To_v1_LabelSelector,
metav1.Convert_v1_LabelSelector_To_Map_string_To_string,
)
if err != nil {
return err
}
// ListOptions is the only options struct which needs conversion (it exposes labels and fields // ListOptions is the only options struct which needs conversion (it exposes labels and fields
// as selectors for convenience). The other types have only a single representation today. // as selectors for convenience). The other types have only a single representation today.
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,

View File

@ -95,9 +95,7 @@ func AddMetaToScheme(scheme *runtime.Scheme) error {
&PartialObjectMetadataList{}, &PartialObjectMetadataList{},
) )
return scheme.AddConversionFuncs( return nil
Convert_Slice_string_To_v1_IncludeObjectPolicy,
)
} }
func init() { func init() {

View File

@ -21,7 +21,6 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library", "//vendor/github.com/gogo/protobuf/proto:go_default_library",
], ],
) )

View File

@ -81,28 +81,27 @@ func init() {
} }
var fileDescriptor_90ec10f86b91f9a8 = []byte{ var fileDescriptor_90ec10f86b91f9a8 = []byte{
// 321 bytes of a gzipped FileDescriptorProto // 317 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0x4b, 0xf3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0x4b, 0xf3, 0x30,
0x18, 0xc7, 0x9b, 0xf7, 0x65, 0x38, 0x3a, 0x04, 0xd9, 0x69, 0xee, 0x90, 0x0d, 0x4f, 0xf3, 0xb0, 0x1c, 0xc6, 0x9b, 0xf7, 0x65, 0x38, 0x3a, 0x04, 0xd9, 0x69, 0xee, 0x90, 0x0d, 0x4f, 0xf3, 0xb0,
0x84, 0x0d, 0x11, 0xc1, 0xdb, 0x6e, 0x82, 0xa2, 0xec, 0x28, 0x1e, 0x4c, 0xbb, 0xc7, 0x2e, 0xd6, 0x84, 0x0d, 0x11, 0xc1, 0xdb, 0x6e, 0x82, 0xa2, 0xec, 0x28, 0x1e, 0x4c, 0xbb, 0xbf, 0x5d, 0xac,
0x34, 0x25, 0x79, 0x3a, 0xf0, 0xe6, 0x47, 0xf0, 0x63, 0xed, 0xb8, 0xe3, 0x40, 0x18, 0xae, 0x7e, 0x69, 0x4a, 0xf2, 0xef, 0xc0, 0x9b, 0x1f, 0xc1, 0x8f, 0xb5, 0xe3, 0x8e, 0x03, 0x61, 0xb8, 0xf8,
0x11, 0x49, 0x57, 0x45, 0xa6, 0x62, 0x6f, 0x79, 0xfe, 0xe1, 0xf7, 0xcb, 0x3f, 0x89, 0x3f, 0x8e, 0x45, 0x24, 0x5d, 0x15, 0x19, 0x0a, 0xbb, 0xf5, 0x79, 0xca, 0xef, 0x97, 0x27, 0x24, 0x1c, 0xa7,
0x4f, 0x2c, 0x93, 0x9a, 0xc7, 0x59, 0x00, 0x26, 0x01, 0x04, 0xcb, 0x67, 0x90, 0x4c, 0xb4, 0xe1, 0x67, 0x96, 0x49, 0xcd, 0xd3, 0x22, 0x02, 0x93, 0x01, 0x82, 0xe5, 0x33, 0xc8, 0x26, 0xda, 0xf0,
0xe5, 0x86, 0x48, 0xa5, 0x12, 0xe1, 0x54, 0x26, 0x60, 0x1e, 0x79, 0x1a, 0x47, 0x2e, 0xb0, 0x5c, 0xea, 0x87, 0xc8, 0xa5, 0x12, 0xf1, 0x54, 0x66, 0x60, 0x9e, 0x79, 0x9e, 0x26, 0xbe, 0xb0, 0x5c,
0x01, 0x0a, 0x3e, 0x1b, 0x04, 0x80, 0x62, 0xc0, 0x23, 0x48, 0xc0, 0x08, 0x84, 0x09, 0x4b, 0x8d, 0x01, 0x0a, 0x3e, 0x1b, 0x44, 0x80, 0x62, 0xc0, 0x13, 0xc8, 0xc0, 0x08, 0x84, 0x09, 0xcb, 0x8d,
0x46, 0xdd, 0x3c, 0xdc, 0xa0, 0xec, 0x2b, 0xca, 0xd2, 0x38, 0x72, 0x81, 0x65, 0x0e, 0x65, 0x25, 0x46, 0xdd, 0x3c, 0xde, 0xa0, 0xec, 0x27, 0xca, 0xf2, 0x34, 0xf1, 0x85, 0x65, 0x1e, 0x65, 0x15,
0xda, 0xee, 0x47, 0x12, 0xa7, 0x59, 0xc0, 0x42, 0xad, 0x78, 0xa4, 0x23, 0xcd, 0x0b, 0x43, 0x90, 0xda, 0xee, 0x27, 0x12, 0xa7, 0x45, 0xc4, 0x62, 0xad, 0x78, 0xa2, 0x13, 0xcd, 0x4b, 0x43, 0x54,
0xdd, 0x15, 0x53, 0x31, 0x14, 0xab, 0x8d, 0xb9, 0x7d, 0x54, 0xa5, 0xd4, 0x76, 0x9f, 0xf6, 0xaf, 0x3c, 0x94, 0xa9, 0x0c, 0xe5, 0xd7, 0xc6, 0xdc, 0x3e, 0xd9, 0x65, 0xd4, 0xf6, 0x9e, 0xf6, 0xe9,
0x57, 0x31, 0x59, 0x82, 0x52, 0xc1, 0x37, 0xe0, 0xf8, 0x2f, 0xc0, 0x86, 0x53, 0x50, 0x62, 0x9b, 0x5f, 0x94, 0x29, 0x32, 0x94, 0x0a, 0xb8, 0x8d, 0xa7, 0xa0, 0xc4, 0x36, 0x77, 0xf4, 0x46, 0xc2,
0x3b, 0x78, 0x21, 0xfe, 0xfe, 0x95, 0x30, 0x28, 0xc5, 0xc3, 0x65, 0x70, 0x0f, 0x21, 0x5e, 0x00, 0xc3, 0x1b, 0x61, 0x50, 0x8a, 0xa7, 0xeb, 0xe8, 0x11, 0x62, 0xbc, 0x02, 0x14, 0x13, 0x81, 0xe2,
0x8a, 0x89, 0x40, 0x71, 0x2e, 0x2d, 0x36, 0x6f, 0xfc, 0xba, 0x2a, 0xe7, 0xd6, 0xbf, 0x2e, 0xe9, 0x52, 0x5a, 0x6c, 0xde, 0x85, 0x75, 0x55, 0xe5, 0xd6, 0xbf, 0x2e, 0xe9, 0x35, 0x86, 0x8c, 0xed,
0x35, 0x86, 0x8c, 0x55, 0x79, 0x29, 0xe6, 0x68, 0x67, 0x1a, 0xed, 0xcd, 0x57, 0x1d, 0x2f, 0x5f, 0x72, 0x71, 0xe6, 0x69, 0x6f, 0x1a, 0x1d, 0xcc, 0x57, 0x9d, 0xc0, 0xad, 0x3a, 0xf5, 0xaf, 0x66,
0x75, 0xea, 0x1f, 0xc9, 0xf8, 0xd3, 0xd8, 0xbc, 0xf5, 0x6b, 0x12, 0x41, 0xd9, 0x16, 0xe9, 0xfe, 0xfc, 0x6d, 0x6c, 0xde, 0x87, 0x35, 0x89, 0xa0, 0x6c, 0x8b, 0x74, 0xff, 0xf7, 0x1a, 0xc3, 0xf3,
0xef, 0x35, 0x86, 0xa7, 0xd5, 0xd4, 0x3f, 0xb6, 0x1d, 0xed, 0x96, 0xe7, 0xd4, 0xce, 0x9c, 0x71, 0xdd, 0xd4, 0xbf, 0xae, 0x1d, 0xed, 0x57, 0xe7, 0xd4, 0x2e, 0xbc, 0x71, 0xbc, 0x11, 0x8f, 0xfa,
0xbc, 0x11, 0x8f, 0xfa, 0xf3, 0x35, 0xf5, 0x16, 0x6b, 0xea, 0x2d, 0xd7, 0xd4, 0x7b, 0xca, 0x29, 0xf3, 0x35, 0x0d, 0x16, 0x6b, 0x1a, 0x2c, 0xd7, 0x34, 0x78, 0x71, 0x94, 0xcc, 0x1d, 0x25, 0x0b,
0x99, 0xe7, 0x94, 0x2c, 0x72, 0x4a, 0x96, 0x39, 0x25, 0xaf, 0x39, 0x25, 0xcf, 0x6f, 0xd4, 0xbb, 0x47, 0xc9, 0xd2, 0x51, 0xf2, 0xee, 0x28, 0x79, 0xfd, 0xa0, 0xc1, 0xed, 0x5e, 0xf5, 0x52, 0x9f,
0xde, 0x29, 0xbf, 0xf6, 0x3d, 0x00, 0x00, 0xff, 0xff, 0xc6, 0x7e, 0x00, 0x08, 0x5a, 0x02, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x82, 0x5b, 0x80, 0x29, 0x02, 0x00, 0x00,
0x00,
} }
func (m *PartialObjectMetadataList) Marshal() (dAtA []byte, err error) { func (m *PartialObjectMetadataList) Marshal() (dAtA []byte, err error) {

View File

@ -22,7 +22,6 @@ syntax = 'proto2';
package k8s.io.apimachinery.pkg.apis.meta.v1beta1; package k8s.io.apimachinery.pkg.apis.meta.v1beta1;
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
// Package-wide variables from generator "generated". // Package-wide variables from generator "generated".

View File

@ -19,7 +19,6 @@ package v1beta1
import ( import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
) )
// GroupName is the group name for this API. // GroupName is the group name for this API.
@ -33,12 +32,6 @@ func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind() return SchemeGroupVersion.WithKind(kind).GroupKind()
} }
// scheme is the registry for the common types that adhere to the meta v1beta1 API spec.
var scheme = runtime.NewScheme()
// ParameterCodec knows about query parameters used with the meta v1beta1 API spec.
var ParameterCodec = runtime.NewParameterCodec(scheme)
// AddMetaToScheme registers base meta types into schemas. // AddMetaToScheme registers base meta types into schemas.
func AddMetaToScheme(scheme *runtime.Scheme) error { func AddMetaToScheme(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
@ -48,14 +41,5 @@ func AddMetaToScheme(scheme *runtime.Scheme) error {
&PartialObjectMetadataList{}, &PartialObjectMetadataList{},
) )
return scheme.AddConversionFuncs( return nil
Convert_Slice_string_To_v1beta1_IncludeObjectPolicy,
)
}
func init() {
utilruntime.Must(AddMetaToScheme(scheme))
// register manually. This usually goes through the SchemeBuilder, which we cannot use here.
utilruntime.Must(RegisterDefaults(scheme))
} }

View File

@ -55,6 +55,7 @@ type Converter struct {
// Set of conversions that should be treated as a no-op // Set of conversions that should be treated as a no-op
ignoredConversions map[typePair]struct{} ignoredConversions map[typePair]struct{}
ignoredUntypedConversions map[typePair]struct{}
// This is a map from a source field type and name, to a list of destination // This is a map from a source field type and name, to a list of destination
// field type and name. // field type and name.
@ -86,6 +87,7 @@ func NewConverter(nameFn NameFunc) *Converter {
conversionFuncs: NewConversionFuncs(), conversionFuncs: NewConversionFuncs(),
generatedConversionFuncs: NewConversionFuncs(), generatedConversionFuncs: NewConversionFuncs(),
ignoredConversions: make(map[typePair]struct{}), ignoredConversions: make(map[typePair]struct{}),
ignoredUntypedConversions: make(map[typePair]struct{}),
nameFunc: nameFn, nameFunc: nameFn,
structFieldDests: make(map[typeNamePair][]typeNamePair), structFieldDests: make(map[typeNamePair][]typeNamePair),
structFieldSources: make(map[typeNamePair][]typeNamePair), structFieldSources: make(map[typeNamePair][]typeNamePair),
@ -93,7 +95,12 @@ func NewConverter(nameFn NameFunc) *Converter {
inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc), inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags), inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags),
} }
c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte) c.RegisterUntypedConversionFunc(
(*[]byte)(nil), (*[]byte)(nil),
func(a, b interface{}, s Scope) error {
return Convert_Slice_byte_To_Slice_byte(a.(*[]byte), b.(*[]byte), s)
},
)
return c return c
} }
@ -153,31 +160,14 @@ type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (so
func NewConversionFuncs() ConversionFuncs { func NewConversionFuncs() ConversionFuncs {
return ConversionFuncs{ return ConversionFuncs{
fns: make(map[typePair]reflect.Value),
untyped: make(map[typePair]ConversionFunc), untyped: make(map[typePair]ConversionFunc),
} }
} }
type ConversionFuncs struct { type ConversionFuncs struct {
fns map[typePair]reflect.Value
untyped map[typePair]ConversionFunc untyped map[typePair]ConversionFunc
} }
// Add adds the provided conversion functions to the lookup table - they must have the signature
// `func(type1, type2, Scope) error`. Functions are added in the order passed and will override
// previously registered pairs.
func (c ConversionFuncs) Add(fns ...interface{}) error {
for _, fn := range fns {
fv := reflect.ValueOf(fn)
ft := fv.Type()
if err := verifyConversionFunctionSignature(ft); err != nil {
return err
}
c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv
}
return nil
}
// AddUntyped adds the provided conversion function to the lookup table for the types that are // AddUntyped adds the provided conversion function to the lookup table for the types that are
// supplied as a and b. a and b must be pointers or an error is returned. This method overwrites // supplied as a and b. a and b must be pointers or an error is returned. This method overwrites
// previously defined functions. // previously defined functions.
@ -197,12 +187,6 @@ func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error {
// both other and c, with other conversions taking precedence. // both other and c, with other conversions taking precedence.
func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
merged := NewConversionFuncs() merged := NewConversionFuncs()
for k, v := range c.fns {
merged.fns[k] = v
}
for k, v := range other.fns {
merged.fns[k] = v
}
for k, v := range c.untyped { for k, v := range c.untyped {
merged.untyped[k] = v merged.untyped[k] = v
} }
@ -360,29 +344,6 @@ func verifyConversionFunctionSignature(ft reflect.Type) error {
return nil return nil
} }
// RegisterConversionFunc registers a conversion func with the
// Converter. conversionFunc must take three parameters: a pointer to the input
// type, a pointer to the output type, and a conversion.Scope (which should be
// used if recursive conversion calls are desired). It must return an error.
//
// Example:
// c.RegisterConversionFunc(
// func(in *Pod, out *v1.Pod, s Scope) error {
// // conversion logic...
// return nil
// })
// DEPRECATED: Will be removed in favor of RegisterUntypedConversionFunc
func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error {
return c.conversionFuncs.Add(conversionFunc)
}
// Similar to RegisterConversionFunc, but registers conversion function that were
// automatically generated.
// DEPRECATED: Will be removed in favor of RegisterGeneratedUntypedConversionFunc
func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error {
return c.generatedConversionFuncs.Add(conversionFunc)
}
// RegisterUntypedConversionFunc registers a function that converts between a and b by passing objects of those // RegisterUntypedConversionFunc registers a function that converts between a and b by passing objects of those
// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
// any other guarantee. // any other guarantee.
@ -409,6 +370,7 @@ func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo) return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
} }
c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{} c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{}
return nil return nil
} }
@ -491,6 +453,11 @@ func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags
flags: flags, flags: flags,
meta: meta, meta: meta,
} }
// ignore conversions of this type
if _, ok := c.ignoredUntypedConversions[pair]; ok {
return nil
}
if fn, ok := c.conversionFuncs.untyped[pair]; ok { if fn, ok := c.conversionFuncs.untyped[pair]; ok {
return fn(src, dest, scope) return fn(src, dest, scope)
} }
@ -517,35 +484,6 @@ func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags
return f(sv, dv, scope) return f(sv, dv, scope)
} }
// callCustom calls 'custom' with sv & dv. custom must be a conversion function.
func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error {
if !sv.CanAddr() {
sv2 := reflect.New(sv.Type())
sv2.Elem().Set(sv)
sv = sv2
} else {
sv = sv.Addr()
}
if !dv.CanAddr() {
if !dv.CanSet() {
return scope.errorf("can't addr or set dest.")
}
dvOrig := dv
dv := reflect.New(dvOrig.Type())
defer func() { dvOrig.Set(dv) }()
} else {
dv = dv.Addr()
}
args := []reflect.Value{sv, dv, reflect.ValueOf(scope)}
ret := custom.Call(args)[0].Interface()
// This convolution is necessary because nil interfaces won't convert
// to errors.
if ret == nil {
return nil
}
return ret.(error)
}
// callUntyped calls predefined conversion func. // callUntyped calls predefined conversion func.
func (c *Converter) callUntyped(sv, dv reflect.Value, f ConversionFunc, scope *scope) error { func (c *Converter) callUntyped(sv, dv reflect.Value, f ConversionFunc, scope *scope) error {
if !dv.CanAddr() { if !dv.CanAddr() {
@ -577,19 +515,6 @@ func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
} }
// Convert sv to dv. // Convert sv to dv.
if fv, ok := c.conversionFuncs.fns[pair]; ok {
if c.Debug != nil {
c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt)
}
return c.callCustom(sv, dv, fv, scope)
}
if fv, ok := c.generatedConversionFuncs.fns[pair]; ok {
if c.Debug != nil {
c.Debug.Logf("Calling generated conversion of '%v' to '%v'", st, dt)
}
return c.callCustom(sv, dv, fv, scope)
}
pair = typePair{reflect.PtrTo(sv.Type()), reflect.PtrTo(dv.Type())} pair = typePair{reflect.PtrTo(sv.Type()), reflect.PtrTo(dv.Type())}
if f, ok := c.conversionFuncs.untyped[pair]; ok { if f, ok := c.conversionFuncs.untyped[pair]; ok {
return c.callUntyped(sv, dv, f, scope) return c.callUntyped(sv, dv, f, scope)

View File

@ -111,24 +111,26 @@ func TestConverter_byteSlice(t *testing.T) {
func TestConverter_MismatchedTypes(t *testing.T) { func TestConverter_MismatchedTypes(t *testing.T) {
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
err := c.RegisterConversionFunc( convertFn := func(in *[]string, out *int, s Scope) error {
func(in *[]string, out *int, s Scope) error {
if str, err := strconv.Atoi((*in)[0]); err != nil { if str, err := strconv.Atoi((*in)[0]); err != nil {
return err return err
} else { } else {
*out = str *out = str
return nil return nil
} }
}
if err := c.RegisterUntypedConversionFunc(
(*[]string)(nil), (*int)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*[]string), b.(*int), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
src := []string{"5"} src := []string{"5"}
var dest *int var dest *int
err = c.Convert(&src, &dest, 0, nil) if err := c.Convert(&src, &dest, 0, nil); err != nil {
if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if e, a := 5, *dest; e != a { if e, a := 5, *dest; e != a {
@ -136,47 +138,6 @@ func TestConverter_MismatchedTypes(t *testing.T) {
} }
} }
func TestConverter_DefaultConvert(t *testing.T) {
type A struct {
Foo string
Baz int
}
type B struct {
Bar string
Baz int
}
c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t)
c.nameFunc = func(t reflect.Type) string { return "MyType" }
// Ensure conversion funcs can call DefaultConvert to get default behavior,
// then fixup remaining fields manually
err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil {
return err
}
out.Bar = in.Foo
return nil
})
if err != nil {
t.Fatalf("unexpected error %v", err)
}
x := A{"hello, intrepid test reader!", 3}
y := B{}
err = c.Convert(&x, &y, 0, nil)
if err != nil {
t.Fatalf("unexpected error %v", err)
}
if e, a := x.Foo, y.Bar; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := x.Baz, y.Baz; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestConverter_DeepCopy(t *testing.T) { func TestConverter_DeepCopy(t *testing.T) {
type A struct { type A struct {
Foo *string Foo *string
@ -229,26 +190,35 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
type C struct{} type C struct{}
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { convertFn1 := func(in *A, out *B, s Scope) error {
out.Bar = in.Foo out.Bar = in.Foo
return s.Convert(&in.Baz, &out.Baz, 0) return s.Convert(&in.Baz, &out.Baz, 0)
}) }
if err != nil { if err := c.RegisterUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
err = c.RegisterConversionFunc(func(in *B, out *A, s Scope) error { convertFn2 := func(in *B, out *A, s Scope) error {
out.Foo = in.Bar out.Foo = in.Bar
return s.Convert(&in.Baz, &out.Baz, 0) return s.Convert(&in.Baz, &out.Baz, 0)
}) }
if err != nil { if err := c.RegisterUntypedConversionFunc(
(*B)(nil), (*A)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*B), b.(*A), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
x := A{"hello, intrepid test reader!", 3} x := A{"hello, intrepid test reader!", 3}
y := B{} y := B{}
err = c.Convert(&x, &y, 0, nil) if err := c.Convert(&x, &y, 0, nil); err != nil {
if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
if e, a := x.Foo, y.Bar; e != a { if e, a := x.Foo, y.Bar; e != a {
@ -261,8 +231,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
z := B{"all your test are belong to us", 42} z := B{"all your test are belong to us", 42}
w := A{} w := A{}
err = c.Convert(&z, &w, 0, nil) if err := c.Convert(&z, &w, 0, nil); err != nil {
if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
if e, a := z.Bar, w.Foo; e != a { if e, a := z.Bar, w.Foo; e != a {
@ -272,14 +241,18 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)
} }
err = c.RegisterConversionFunc(func(in *A, out *C, s Scope) error { convertFn3 := func(in *A, out *C, s Scope) error {
return fmt.Errorf("C can't store an A, silly") return fmt.Errorf("C can't store an A, silly")
}) }
if err != nil { if err := c.RegisterUntypedConversionFunc(
(*A)(nil), (*C)(nil),
func(a, b interface{}, s Scope) error {
return convertFn3(a.(*A), b.(*C), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
err = c.Convert(&A{}, &C{}, 0, nil) if err := c.Convert(&A{}, &C{}, 0, nil); err == nil {
if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
} }
@ -290,10 +263,16 @@ func TestConverter_IgnoredConversion(t *testing.T) {
count := 0 count := 0
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { convertFn := func(in *A, out *B, s Scope) error {
count++ count++
return nil return nil
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil { if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil {
@ -337,14 +316,26 @@ func TestConverter_GeneratedConversionOverridden(t *testing.T) {
type A struct{} type A struct{}
type B struct{} type B struct{}
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { convertFn1 := func(in *A, out *B, s Scope) error {
return nil return nil
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error { convertFn2 := func(in *A, out *B, s Scope) error {
return fmt.Errorf("generated function should be overridden") return fmt.Errorf("generated function should be overridden")
}); err != nil { }
if err := c.RegisterGeneratedUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
@ -359,21 +350,36 @@ func TestConverter_WithConversionOverridden(t *testing.T) {
type A struct{} type A struct{}
type B struct{} type B struct{}
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { convertFn1 := func(in *A, out *B, s Scope) error {
return fmt.Errorf("conversion function should be overridden") return fmt.Errorf("conversion function should be overridden")
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error { convertFn2 := func(in *A, out *B, s Scope) error {
return fmt.Errorf("generated function should be overridden") return fmt.Errorf("generated function should be overridden")
}); err != nil { }
if err := c.RegisterGeneratedUntypedConversionFunc(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*A), b.(*B), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
ext := NewConversionFuncs() ext := NewConversionFuncs()
ext.Add(func(in *A, out *B, s Scope) error { ext.AddUntyped(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return nil return nil
}) },
)
newc := c.WithConversions(ext) newc := c.WithConversions(ext)
a := A{} a := A{}
@ -394,13 +400,19 @@ func TestConverter_MapsStringArrays(t *testing.T) {
} }
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error { convertFn1 := func(input *[]string, out *string, s Scope) error {
if len(*input) == 0 { if len(*input) == 0 {
*out = "" *out = ""
} }
*out = (*input)[0] *out = (*input)[0]
return nil return nil
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*[]string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*[]string), b.(*string), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
@ -416,7 +428,7 @@ func TestConverter_MapsStringArrays(t *testing.T) {
t.Error("unexpected non-error") t.Error("unexpected non-error")
} }
if err := c.RegisterConversionFunc(func(input *[]string, out *int, s Scope) error { convertFn2 := func(input *[]string, out *int, s Scope) error {
if len(*input) == 0 { if len(*input) == 0 {
*out = 0 *out = 0
} }
@ -427,7 +439,13 @@ func TestConverter_MapsStringArrays(t *testing.T) {
} }
*out = i *out = i
return nil return nil
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*[]string)(nil), (*int)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*[]string), b.(*int), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
@ -447,13 +465,19 @@ func TestConverter_MapsStringArraysWithMappingKey(t *testing.T) {
} }
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error { convertFn := func(input *[]string, out *string, s Scope) error {
if len(*input) == 0 { if len(*input) == 0 {
*out = "" *out = ""
} }
*out = (*input)[0] *out = (*input)[0]
return nil return nil
}); err != nil { }
if err := c.RegisterUntypedConversionFunc(
(*[]string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*[]string), b.(*string), s)
},
); err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
@ -536,39 +560,43 @@ func TestConverter_MapElemAddr(t *testing.T) {
} }
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
err := c.RegisterConversionFunc( convertFn1 := func(in *int, out *string, s Scope) error {
func(in *int, out *string, s Scope) error {
*out = fmt.Sprintf("%v", *in) *out = fmt.Sprintf("%v", *in)
return nil return nil
}
if err := c.RegisterUntypedConversionFunc(
(*int)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*int), b.(*string), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
err = c.RegisterConversionFunc( convertFn2 := func(in *string, out *int, s Scope) error {
func(in *string, out *int, s Scope) error {
if str, err := strconv.Atoi(*in); err != nil { if str, err := strconv.Atoi(*in); err != nil {
return err return err
} else { } else {
*out = str *out = str
return nil return nil
} }
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*int)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*string), b.(*int), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
f := fuzz.New().NilChance(0).NumElements(3, 3) f := fuzz.New().NilChance(0).NumElements(3, 3)
first := Foo{} first := Foo{}
second := Bar{} second := Bar{}
f.Fuzz(&first) f.Fuzz(&first)
err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil) if err := c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
third := Foo{} third := Foo{}
err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil) if err := c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil); err != nil {
if err != nil {
t.Fatalf("error on Convert: %v", err) t.Fatalf("error on Convert: %v", err)
} }
if e, a := first, third; !reflect.DeepEqual(e, a) { if e, a := first, third; !reflect.DeepEqual(e, a) {
@ -585,8 +613,7 @@ func TestConverter_tags(t *testing.T) {
} }
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
err := c.RegisterConversionFunc( convertFn := func(in *string, out *string, s Scope) error {
func(in *string, out *string, s Scope) error {
if e, a := "foo", s.SrcTag().Get("test"); e != a { if e, a := "foo", s.SrcTag().Get("test"); e != a {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)
} }
@ -594,13 +621,16 @@ func TestConverter_tags(t *testing.T) {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)
} }
return nil return nil
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*string), b.(*string), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil) if err := c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
} }
@ -611,33 +641,38 @@ func TestConverter_meta(t *testing.T) {
c := NewConverter(DefaultNameFunc) c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t) c.Debug = testLogger(t)
checks := 0 checks := 0
err := c.RegisterConversionFunc( convertFn1 := func(in *Foo, out *Bar, s Scope) error {
func(in *Foo, out *Bar, s Scope) error {
if s.Meta() == nil { if s.Meta() == nil {
t.Errorf("Meta did not get passed!") t.Errorf("Meta did not get passed!")
} }
checks++ checks++
s.Convert(&in.A, &out.A, 0) s.Convert(&in.A, &out.A, 0)
return nil return nil
}
if err := c.RegisterUntypedConversionFunc(
(*Foo)(nil), (*Bar)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*Foo), b.(*Bar), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
err = c.RegisterConversionFunc( convertFn2 := func(in *string, out *string, s Scope) error {
func(in *string, out *string, s Scope) error {
if s.Meta() == nil { if s.Meta() == nil {
t.Errorf("Meta did not get passed a second time!") t.Errorf("Meta did not get passed a second time!")
} }
checks++ checks++
return nil return nil
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*string), b.(*string), s)
}, },
) ); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{}) if err := c.Convert(&Foo{}, &Bar{}, 0, &Meta{}); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if checks != 2 { if checks != 2 {

View File

@ -308,45 +308,6 @@ func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
return s.converter.RegisterIgnoredConversion(from, to) return s.converter.RegisterIgnoredConversion(from, to)
} }
// AddConversionFuncs adds functions to the list of conversion functions. The given
// functions should know how to convert between two of your API objects, or their
// sub-objects. We deduce how to call these functions from the types of their two
// parameters; see the comment for Converter.Register.
//
// Note that, if you need to copy sub-objects that didn't change, you can use the
// conversion.Scope object that will be passed to your conversion function.
// Additionally, all conversions started by Scheme will set the SrcVersion and
// DestVersion fields on the Meta object. Example:
//
// s.AddConversionFuncs(
// func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error {
// // You can depend on Meta() being non-nil, and this being set to
// // the source version, e.g., ""
// s.Meta().SrcVersion
// // You can depend on this being set to the destination version,
// // e.g., "v1".
// s.Meta().DestVersion
// // Call scope.Convert to copy sub-fields.
// s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0)
// return nil
// },
// )
//
// (For more detail about conversion functions, see Converter.Register's comment.)
//
// Also note that the default behavior, if you don't add a conversion function, is to
// sanely copy fields that have the same names and same type names. It's OK if the
// destination type has extra fields, but it must not remove any. So you only need to
// add conversion functions for things with changed/removed fields.
func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
for _, f := range conversionFuncs {
if err := s.converter.RegisterConversionFunc(f); err != nil {
return err
}
}
return nil
}
// AddConversionFunc registers a function that converts between a and b by passing objects of those // AddConversionFunc registers a function that converts between a and b by passing objects of those
// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
// any other guarantee. // any other guarantee.

View File

@ -31,6 +31,47 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
) )
type testConversions struct {
internalToExternalCalls int
externalToInternalCalls int
}
func (c *testConversions) internalToExternalSimple(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
if err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := scope.Convert(&in.TestString, &out.TestString, 0); err != nil {
return err
}
c.internalToExternalCalls++
return nil
}
func (c *testConversions) externalToInternalSimple(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error {
if err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := scope.Convert(&in.TestString, &out.TestString, 0); err != nil {
return err
}
c.externalToInternalCalls++
return nil
}
func (c *testConversions) registerConversions(s *runtime.Scheme) error {
if err := s.AddConversionFunc((*runtimetesting.InternalSimple)(nil), (*runtimetesting.ExternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
return c.internalToExternalSimple(a.(*runtimetesting.InternalSimple), b.(*runtimetesting.ExternalSimple), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*runtimetesting.ExternalSimple)(nil), (*runtimetesting.InternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
return c.externalToInternalSimple(a.(*runtimetesting.ExternalSimple), b.(*runtimetesting.InternalSimple), scope)
}); err != nil {
return err
}
return nil
}
func TestScheme(t *testing.T) { func TestScheme(t *testing.T) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
internalGVK := internalGV.WithKind("Simple") internalGVK := internalGV.WithKind("Simple")
@ -47,37 +88,13 @@ func TestScheme(t *testing.T) {
// test that scheme is an ObjectTyper // test that scheme is an ObjectTyper
var _ runtime.ObjectTyper = scheme var _ runtime.ObjectTyper = scheme
internalToExternalCalls := 0 conversions := &testConversions{
externalToInternalCalls := 0 internalToExternalCalls: 0,
externalToInternalCalls: 0,
}
// Register functions to verify that scope.Meta() gets set correctly. // Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs( if err := conversions.registerConversions(scheme); err != nil {
func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
if err != nil {
return err
}
err = scope.Convert(&in.TestString, &out.TestString, 0)
if err != nil {
return err
}
internalToExternalCalls++
return nil
},
func(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error {
err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
if err != nil {
return err
}
err = scope.Convert(&in.TestString, &out.TestString, 0)
if err != nil {
return err
}
externalToInternalCalls++
return nil
},
)
if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -133,8 +150,7 @@ func TestScheme(t *testing.T) {
} }
external := &runtimetesting.ExternalSimple{} external := &runtimetesting.ExternalSimple{}
err = scheme.Convert(simple, external, nil) if err := scheme.Convert(simple, external, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if e, a := simple.TestString, external.TestString; e != a { if e, a := simple.TestString, external.TestString; e != a {
@ -147,12 +163,11 @@ func TestScheme(t *testing.T) {
} }
unstructuredObj := &runtimetesting.Unstructured{} unstructuredObj := &runtimetesting.Unstructured{}
err = scheme.Convert(simple, unstructuredObj, nil) err := scheme.Convert(simple, unstructuredObj, nil)
if err == nil || !strings.Contains(err.Error(), "to Unstructured without providing a preferred version to convert to") { if err == nil || !strings.Contains(err.Error(), "to Unstructured without providing a preferred version to convert to") {
t.Fatalf("Unexpected non-error: %v", err) t.Fatalf("Unexpected non-error: %v", err)
} }
err = scheme.Convert(simple, unstructuredObj, externalGV) if err := scheme.Convert(simple, unstructuredObj, externalGV); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a { if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
@ -171,8 +186,7 @@ func TestScheme(t *testing.T) {
TestString: "foo", TestString: "foo",
} }
err = scheme.Convert(external, unstructuredObj, nil) if err := scheme.Convert(external, unstructuredObj, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a { if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a {
@ -187,8 +201,7 @@ func TestScheme(t *testing.T) {
"test": []interface{}{"other", "test"}, "test": []interface{}{"other", "test"},
}} }}
uOut := &runtimetesting.Unstructured{} uOut := &runtimetesting.Unstructured{}
err = scheme.Convert(uIn, uOut, nil) if err := scheme.Convert(uIn, uOut, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if !reflect.DeepEqual(uIn.Object, uOut.Object) { if !reflect.DeepEqual(uIn.Object, uOut.Object) {
@ -203,8 +216,7 @@ func TestScheme(t *testing.T) {
} }
unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple")) unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple"))
externalOut := &runtimetesting.ExternalSimple{} externalOut := &runtimetesting.ExternalSimple{}
err = scheme.Convert(unstructuredObj, externalOut, nil) if err := scheme.Convert(unstructuredObj, externalOut, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if externalOut.TestString != "bla" { if externalOut.TestString != "bla" {
@ -212,12 +224,12 @@ func TestScheme(t *testing.T) {
} }
}) })
t.Run("Encode and Convert should each have caused an increment", func(t *testing.T) { t.Run("Encode and Convert should each have caused an increment", func(t *testing.T) {
if e, a := 3, internalToExternalCalls; e != a { if e, a := 3, conversions.internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a) t.Errorf("Expected %v, got %v", e, a)
} }
}) })
t.Run("DecodeInto and Decode should each have caused an increment because of a conversion", func(t *testing.T) { t.Run("DecodeInto and Decode should each have caused an increment because of a conversion", func(t *testing.T) {
if e, a := 2, externalToInternalCalls; e != a { if e, a := 2, conversions.externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a) t.Errorf("Expected %v, got %v", e, a)
} }
}) })
@ -481,9 +493,12 @@ func GetTestScheme() *runtime.Scheme {
s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{}) s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{}) s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{})
utilruntime.Must(s.AddConversionFuncs(func(in *runtimetesting.TestType1, out *runtimetesting.ExternalTestType1, s conversion.Scope) error { convertTestType := func(in *runtimetesting.TestType1, out *runtimetesting.ExternalTestType1, s conversion.Scope) error {
out.A = in.A out.A = in.A
return nil return nil
}
utilruntime.Must(s.AddConversionFunc((*runtimetesting.TestType1)(nil), (*runtimetesting.ExternalTestType1)(nil), func(a, b interface{}, scope conversion.Scope) error {
return convertTestType(a.(*runtimetesting.TestType1), b.(*runtimetesting.ExternalTestType1), scope)
})) }))
return s return s
} }
@ -931,25 +946,13 @@ func TestMetaValues(t *testing.T) {
s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{}) s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{}) s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
internalToExternalCalls := 0 conversions := &testConversions{
externalToInternalCalls := 0 internalToExternalCalls: 0,
externalToInternalCalls: 0,
}
// Register functions to verify that scope.Meta() gets set correctly. // Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs( if err := conversions.registerConversions(s); err != nil {
func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
t.Logf("internal -> external")
scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++
return nil
},
func(in *runtimetesting.ExternalSimple, out *runtimetesting.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) t.Fatalf("unexpected error: %v", err)
} }
simple := &runtimetesting.InternalSimple{ simple := &runtimetesting.InternalSimple{
@ -972,10 +975,10 @@ func TestMetaValues(t *testing.T) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
} }
if e, a := 1, internalToExternalCalls; e != a { if e, a := 1, conversions.internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a) t.Errorf("Expected %v, got %v", e, a)
} }
if e, a := 1, externalToInternalCalls; e != a { if e, a := 1, conversions.externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a) t.Errorf("Expected %v, got %v", e, a)
} }
} }
@ -997,21 +1000,20 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
internalToExternalCalls := 0 internalToExternalCalls := 0
// Register functions to verify that scope.Meta() gets set correctly. // Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs( convertSimple := func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TestString, &out.TestString, 0) scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++ internalToExternalCalls++
return nil return nil
}, }
) if err := s.AddConversionFunc((*InternalSimple)(nil), (*ExternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
if err != nil { return convertSimple(a.(*InternalSimple), b.(*ExternalSimple), scope)
}); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
simple := &InternalSimple{TestString: "foo"} simple := &InternalSimple{TestString: "foo"}
external := &ExternalSimple{} external := &ExternalSimple{}
err = s.Convert(simple, external, nil) if err := s.Convert(simple, external, nil); err != nil {
if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
if e, a := simple.TestString, external.TestString; e != a { if e, a := simple.TestString, external.TestString; e != a {