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 {
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
// as selectors for convenience). The other types have only a single representation today.
scheme.AddKnownTypes(SchemeGroupVersion,

View File

@ -95,9 +95,7 @@ func AddMetaToScheme(scheme *runtime.Scheme) error {
&PartialObjectMetadataList{},
)
return scheme.AddConversionFuncs(
Convert_Slice_string_To_v1_IncludeObjectPolicy,
)
return nil
}
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/runtime: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",
],
)

View File

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

View File

@ -22,7 +22,6 @@ syntax = 'proto2';
package k8s.io.apimachinery.pkg.apis.meta.v1beta1;
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";
// Package-wide variables from generator "generated".

View File

@ -19,7 +19,6 @@ package v1beta1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
// GroupName is the group name for this API.
@ -33,12 +32,6 @@ func Kind(kind string) schema.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.
func AddMetaToScheme(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
@ -48,14 +41,5 @@ func AddMetaToScheme(scheme *runtime.Scheme) error {
&PartialObjectMetadataList{},
)
return scheme.AddConversionFuncs(
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))
return nil
}

View File

@ -54,7 +54,8 @@ type Converter struct {
generatedConversionFuncs ConversionFuncs
// 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
// field type and name.
@ -83,17 +84,23 @@ type Converter struct {
// NewConverter creates a new Converter object.
func NewConverter(nameFn NameFunc) *Converter {
c := &Converter{
conversionFuncs: NewConversionFuncs(),
generatedConversionFuncs: NewConversionFuncs(),
ignoredConversions: make(map[typePair]struct{}),
nameFunc: nameFn,
structFieldDests: make(map[typeNamePair][]typeNamePair),
structFieldSources: make(map[typeNamePair][]typeNamePair),
conversionFuncs: NewConversionFuncs(),
generatedConversionFuncs: NewConversionFuncs(),
ignoredConversions: make(map[typePair]struct{}),
ignoredUntypedConversions: make(map[typePair]struct{}),
nameFunc: nameFn,
structFieldDests: make(map[typeNamePair][]typeNamePair),
structFieldSources: make(map[typeNamePair][]typeNamePair),
inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
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
}
@ -153,31 +160,14 @@ type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (so
func NewConversionFuncs() ConversionFuncs {
return ConversionFuncs{
fns: make(map[typePair]reflect.Value),
untyped: make(map[typePair]ConversionFunc),
}
}
type ConversionFuncs struct {
fns map[typePair]reflect.Value
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
// supplied as a and b. a and b must be pointers or an error is returned. This method overwrites
// 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.
func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
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 {
merged.untyped[k] = v
}
@ -360,29 +344,6 @@ func verifyConversionFunctionSignature(ft reflect.Type) error {
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
// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
// 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)
}
c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{}
return nil
}
@ -491,6 +453,11 @@ func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags
flags: flags,
meta: meta,
}
// ignore conversions of this type
if _, ok := c.ignoredUntypedConversions[pair]; ok {
return nil
}
if fn, ok := c.conversionFuncs.untyped[pair]; ok {
return fn(src, dest, scope)
}
@ -517,35 +484,6 @@ func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags
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.
func (c *Converter) callUntyped(sv, dv reflect.Value, f ConversionFunc, scope *scope) error {
if !dv.CanAddr() {
@ -577,19 +515,6 @@ func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
}
// 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())}
if f, ok := c.conversionFuncs.untyped[pair]; ok {
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) {
c := NewConverter(DefaultNameFunc)
err := c.RegisterConversionFunc(
func(in *[]string, out *int, s Scope) error {
if str, err := strconv.Atoi((*in)[0]); err != nil {
return err
} else {
*out = str
return nil
}
convertFn := func(in *[]string, out *int, s Scope) error {
if str, err := strconv.Atoi((*in)[0]); err != nil {
return err
} else {
*out = str
return nil
}
}
if err := c.RegisterUntypedConversionFunc(
(*[]string)(nil), (*int)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*[]string), b.(*int), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
src := []string{"5"}
var dest *int
err = c.Convert(&src, &dest, 0, nil)
if err != nil {
if err := c.Convert(&src, &dest, 0, nil); err != nil {
t.Fatalf("unexpected error: %v", err)
}
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) {
type A struct {
Foo *string
@ -229,26 +190,35 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
type C struct{}
c := NewConverter(DefaultNameFunc)
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
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)
}
err = c.RegisterConversionFunc(func(in *B, out *A, s Scope) error {
convertFn2 := func(in *B, out *A, s Scope) error {
out.Foo = in.Bar
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)
}
x := A{"hello, intrepid test reader!", 3}
y := B{}
err = c.Convert(&x, &y, 0, nil)
if err != nil {
if err := c.Convert(&x, &y, 0, nil); err != nil {
t.Fatalf("unexpected error %v", err)
}
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}
w := A{}
err = c.Convert(&z, &w, 0, nil)
if err != nil {
if err := c.Convert(&z, &w, 0, nil); err != nil {
t.Fatalf("unexpected error %v", err)
}
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)
}
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")
})
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)
}
err = c.Convert(&A{}, &C{}, 0, nil)
if err == nil {
if err := c.Convert(&A{}, &C{}, 0, nil); err == nil {
t.Errorf("unexpected non-error")
}
}
@ -290,10 +263,16 @@ func TestConverter_IgnoredConversion(t *testing.T) {
count := 0
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++
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)
}
if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil {
@ -337,14 +316,26 @@ func TestConverter_GeneratedConversionOverridden(t *testing.T) {
type A struct{}
type B struct{}
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
}); 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)
}
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")
}); 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)
}
@ -359,21 +350,36 @@ func TestConverter_WithConversionOverridden(t *testing.T) {
type A struct{}
type B struct{}
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")
}); 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)
}
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")
}); 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)
}
ext := NewConversionFuncs()
ext.Add(func(in *A, out *B, s Scope) error {
return nil
})
ext.AddUntyped(
(*A)(nil), (*B)(nil),
func(a, b interface{}, s Scope) error {
return nil
},
)
newc := c.WithConversions(ext)
a := A{}
@ -394,13 +400,19 @@ func TestConverter_MapsStringArrays(t *testing.T) {
}
c := NewConverter(DefaultNameFunc)
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 {
*out = ""
}
*out = (*input)[0]
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)
}
@ -416,7 +428,7 @@ func TestConverter_MapsStringArrays(t *testing.T) {
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 {
*out = 0
}
@ -427,7 +439,13 @@ func TestConverter_MapsStringArrays(t *testing.T) {
}
*out = i
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)
}
@ -447,13 +465,19 @@ func TestConverter_MapsStringArraysWithMappingKey(t *testing.T) {
}
c := NewConverter(DefaultNameFunc)
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 {
*out = ""
}
*out = (*input)[0]
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)
}
@ -536,39 +560,43 @@ func TestConverter_MapElemAddr(t *testing.T) {
}
c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t)
err := c.RegisterConversionFunc(
func(in *int, out *string, s Scope) error {
*out = fmt.Sprintf("%v", *in)
return nil
convertFn1 := func(in *int, out *string, s Scope) error {
*out = fmt.Sprintf("%v", *in)
return nil
}
if err := c.RegisterUntypedConversionFunc(
(*int)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*int), b.(*string), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = c.RegisterConversionFunc(
func(in *string, out *int, s Scope) error {
if str, err := strconv.Atoi(*in); err != nil {
return err
} else {
*out = str
return nil
}
convertFn2 := func(in *string, out *int, s Scope) error {
if str, err := strconv.Atoi(*in); err != nil {
return err
} else {
*out = str
return nil
}
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*int)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*string), b.(*int), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
f := fuzz.New().NilChance(0).NumElements(3, 3)
first := Foo{}
second := Bar{}
f.Fuzz(&first)
err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil)
if err != nil {
if err := c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
third := Foo{}
err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil)
if err != nil {
if err := c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil); err != nil {
t.Fatalf("error on Convert: %v", err)
}
if e, a := first, third; !reflect.DeepEqual(e, a) {
@ -585,22 +613,24 @@ func TestConverter_tags(t *testing.T) {
}
c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t)
err := c.RegisterConversionFunc(
func(in *string, out *string, s Scope) error {
if e, a := "foo", s.SrcTag().Get("test"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", s.DestTag().Get("test"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
return nil
convertFn := func(in *string, out *string, s Scope) error {
if e, a := "foo", s.SrcTag().Get("test"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", s.DestTag().Get("test"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
return nil
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn(a.(*string), b.(*string), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil)
if err != nil {
if err := c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
}
@ -611,33 +641,38 @@ func TestConverter_meta(t *testing.T) {
c := NewConverter(DefaultNameFunc)
c.Debug = testLogger(t)
checks := 0
err := c.RegisterConversionFunc(
func(in *Foo, out *Bar, s Scope) error {
if s.Meta() == nil {
t.Errorf("Meta did not get passed!")
}
checks++
s.Convert(&in.A, &out.A, 0)
return nil
convertFn1 := func(in *Foo, out *Bar, s Scope) error {
if s.Meta() == nil {
t.Errorf("Meta did not get passed!")
}
checks++
s.Convert(&in.A, &out.A, 0)
return nil
}
if err := c.RegisterUntypedConversionFunc(
(*Foo)(nil), (*Bar)(nil),
func(a, b interface{}, s Scope) error {
return convertFn1(a.(*Foo), b.(*Bar), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = c.RegisterConversionFunc(
func(in *string, out *string, s Scope) error {
if s.Meta() == nil {
t.Errorf("Meta did not get passed a second time!")
}
checks++
return nil
convertFn2 := func(in *string, out *string, s Scope) error {
if s.Meta() == nil {
t.Errorf("Meta did not get passed a second time!")
}
checks++
return nil
}
if err := c.RegisterUntypedConversionFunc(
(*string)(nil), (*string)(nil),
func(a, b interface{}, s Scope) error {
return convertFn2(a.(*string), b.(*string), s)
},
)
if err != nil {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{})
if err != nil {
if err := c.Convert(&Foo{}, &Bar{}, 0, &Meta{}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if checks != 2 {

View File

@ -308,45 +308,6 @@ func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
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
// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
// any other guarantee.

View File

@ -31,6 +31,47 @@ import (
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) {
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
internalGVK := internalGV.WithKind("Simple")
@ -47,37 +88,13 @@ func TestScheme(t *testing.T) {
// test that scheme is an ObjectTyper
var _ runtime.ObjectTyper = scheme
internalToExternalCalls := 0
externalToInternalCalls := 0
conversions := &testConversions{
internalToExternalCalls: 0,
externalToInternalCalls: 0,
}
// Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs(
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 {
if err := conversions.registerConversions(scheme); err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -133,8 +150,7 @@ func TestScheme(t *testing.T) {
}
external := &runtimetesting.ExternalSimple{}
err = scheme.Convert(simple, external, nil)
if err != nil {
if err := scheme.Convert(simple, external, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {
@ -147,12 +163,11 @@ func TestScheme(t *testing.T) {
}
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") {
t.Fatalf("Unexpected non-error: %v", err)
}
err = scheme.Convert(simple, unstructuredObj, externalGV)
if err != nil {
if err := scheme.Convert(simple, unstructuredObj, externalGV); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
@ -171,8 +186,7 @@ func TestScheme(t *testing.T) {
TestString: "foo",
}
err = scheme.Convert(external, unstructuredObj, nil)
if err != nil {
if err := scheme.Convert(external, unstructuredObj, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a {
@ -187,8 +201,7 @@ func TestScheme(t *testing.T) {
"test": []interface{}{"other", "test"},
}}
uOut := &runtimetesting.Unstructured{}
err = scheme.Convert(uIn, uOut, nil)
if err != nil {
if err := scheme.Convert(uIn, uOut, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(uIn.Object, uOut.Object) {
@ -203,8 +216,7 @@ func TestScheme(t *testing.T) {
}
unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple"))
externalOut := &runtimetesting.ExternalSimple{}
err = scheme.Convert(unstructuredObj, externalOut, nil)
if err != nil {
if err := scheme.Convert(unstructuredObj, externalOut, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
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) {
if e, a := 3, internalToExternalCalls; e != a {
if e, a := 3, conversions.internalToExternalCalls; 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) {
if e, a := 2, externalToInternalCalls; e != a {
if e, a := 2, conversions.externalToInternalCalls; 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.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
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
}
@ -931,25 +946,13 @@ func TestMetaValues(t *testing.T) {
s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
internalToExternalCalls := 0
externalToInternalCalls := 0
conversions := &testConversions{
internalToExternalCalls: 0,
externalToInternalCalls: 0,
}
// Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs(
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 {
if err := conversions.registerConversions(s); err != nil {
t.Fatalf("unexpected error: %v", err)
}
simple := &runtimetesting.InternalSimple{
@ -972,10 +975,10 @@ func TestMetaValues(t *testing.T) {
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)
}
if e, a := 1, externalToInternalCalls; e != a {
if e, a := 1, conversions.externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
@ -997,21 +1000,20 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
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 {
convertSimple := func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++
return nil
}
if err := s.AddConversionFunc((*InternalSimple)(nil), (*ExternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
return convertSimple(a.(*InternalSimple), b.(*ExternalSimple), scope)
}); err != nil {
t.Fatalf("unexpected error: %v", err)
}
simple := &InternalSimple{TestString: "foo"}
external := &ExternalSimple{}
err = s.Convert(simple, external, nil)
if err != nil {
if err := s.Convert(simple, external, nil); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {