github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/scheme_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package runtime_test
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/conversion"
    26  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime"
    27  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    28  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer"
    29  	runtimetesting "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/testing"
    30  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/diff"
    31  	utilruntime "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/runtime"
    32  )
    33  
    34  type testConversions struct {
    35  	internalToExternalCalls int
    36  	externalToInternalCalls int
    37  }
    38  
    39  func (c *testConversions) internalToExternalSimple(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
    40  	out.TypeMeta = in.TypeMeta
    41  	out.TestString = in.TestString
    42  	c.internalToExternalCalls++
    43  	return nil
    44  }
    45  
    46  func (c *testConversions) externalToInternalSimple(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error {
    47  	out.TypeMeta = in.TypeMeta
    48  	out.TestString = in.TestString
    49  	c.externalToInternalCalls++
    50  	return nil
    51  }
    52  
    53  func (c *testConversions) registerConversions(s *runtime.Scheme) error {
    54  	if err := s.AddConversionFunc((*runtimetesting.InternalSimple)(nil), (*runtimetesting.ExternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
    55  		return c.internalToExternalSimple(a.(*runtimetesting.InternalSimple), b.(*runtimetesting.ExternalSimple), scope)
    56  	}); err != nil {
    57  		return err
    58  	}
    59  	if err := s.AddConversionFunc((*runtimetesting.ExternalSimple)(nil), (*runtimetesting.InternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
    60  		return c.externalToInternalSimple(a.(*runtimetesting.ExternalSimple), b.(*runtimetesting.InternalSimple), scope)
    61  	}); err != nil {
    62  		return err
    63  	}
    64  	return nil
    65  }
    66  
    67  func TestScheme(t *testing.T) {
    68  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
    69  	internalGVK := internalGV.WithKind("Simple")
    70  	externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
    71  	externalGVK := externalGV.WithKind("Simple")
    72  
    73  	scheme := runtime.NewScheme()
    74  	scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{})
    75  	scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{})
    76  	utilruntime.Must(runtimetesting.RegisterConversions(scheme))
    77  
    78  	// If set, would clear TypeMeta during conversion.
    79  	//scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{})
    80  
    81  	// test that scheme is an ObjectTyper
    82  	var _ runtime.ObjectTyper = scheme
    83  
    84  	conversions := &testConversions{
    85  		internalToExternalCalls: 0,
    86  		externalToInternalCalls: 0,
    87  	}
    88  
    89  	// Register functions to verify that scope.Meta() gets set correctly.
    90  	utilruntime.Must(conversions.registerConversions(scheme))
    91  
    92  	t.Run("Encode, Decode, DecodeInto, and DecodeToVersion", func(t *testing.T) {
    93  		simple := &runtimetesting.InternalSimple{
    94  			TestString: "foo",
    95  		}
    96  
    97  		codecs := serializer.NewCodecFactory(scheme)
    98  		codec := codecs.LegacyCodec(externalGV)
    99  		info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
   100  		jsonserializer := info.Serializer
   101  
   102  		obj := runtime.Object(simple)
   103  		data, err := runtime.Encode(codec, obj)
   104  		if err != nil {
   105  			t.Fatal(err)
   106  		}
   107  
   108  		obj2, err := runtime.Decode(codec, data)
   109  		if err != nil {
   110  			t.Fatal(err)
   111  		}
   112  		if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
   113  			t.Fatalf("Got wrong type")
   114  		}
   115  		if e, a := simple, obj2; !reflect.DeepEqual(e, a) {
   116  			t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
   117  		}
   118  
   119  		obj3 := &runtimetesting.InternalSimple{}
   120  		if err := runtime.DecodeInto(codec, data, obj3); err != nil {
   121  			t.Fatal(err)
   122  		}
   123  		// clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion
   124  		// does not automatically clear TypeMeta anymore).
   125  		simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()}
   126  		if e, a := simple, obj3; !reflect.DeepEqual(e, a) {
   127  			t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
   128  		}
   129  
   130  		obj4, err := runtime.Decode(jsonserializer, data)
   131  		if err != nil {
   132  			t.Fatal(err)
   133  		}
   134  		if _, ok := obj4.(*runtimetesting.ExternalSimple); !ok {
   135  			t.Fatalf("Got wrong type")
   136  		}
   137  	})
   138  	t.Run("Convert", func(t *testing.T) {
   139  		simple := &runtimetesting.InternalSimple{
   140  			TestString: "foo",
   141  		}
   142  
   143  		external := &runtimetesting.ExternalSimple{}
   144  		if err := scheme.Convert(simple, external, nil); err != nil {
   145  			t.Fatalf("Unexpected error: %v", err)
   146  		}
   147  		if e, a := simple.TestString, external.TestString; e != a {
   148  			t.Errorf("Expected %q, got %q", e, a)
   149  		}
   150  	})
   151  	t.Run("Convert internal to unstructured", func(t *testing.T) {
   152  		simple := &runtimetesting.InternalSimple{
   153  			TestString: "foo",
   154  		}
   155  
   156  		unstructuredObj := &runtimetesting.Unstructured{}
   157  		err := scheme.Convert(simple, unstructuredObj, nil)
   158  		if err == nil || !strings.Contains(err.Error(), "to Unstructured without providing a preferred version to convert to") {
   159  			t.Fatalf("Unexpected non-error: %v", err)
   160  		}
   161  		if err := scheme.Convert(simple, unstructuredObj, externalGV); err != nil {
   162  			t.Fatalf("Unexpected error: %v", err)
   163  		}
   164  		if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
   165  			t.Errorf("Expected %q, got %q", e, a)
   166  		}
   167  		if e := unstructuredObj.GetObjectKind().GroupVersionKind(); e != externalGVK {
   168  			t.Errorf("Unexpected object kind: %#v", e)
   169  		}
   170  		if gvks, unversioned, err := scheme.ObjectKinds(unstructuredObj); err != nil || gvks[0] != externalGVK || unversioned {
   171  			t.Errorf("Scheme did not recognize unversioned: %v, %#v %t", err, gvks, unversioned)
   172  		}
   173  	})
   174  	t.Run("Convert external to unstructured", func(t *testing.T) {
   175  		unstructuredObj := &runtimetesting.Unstructured{}
   176  		external := &runtimetesting.ExternalSimple{
   177  			TestString: "foo",
   178  		}
   179  
   180  		if err := scheme.Convert(external, unstructuredObj, nil); err != nil {
   181  			t.Fatalf("Unexpected error: %v", err)
   182  		}
   183  		if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a {
   184  			t.Errorf("Expected %q, got %q", e, a)
   185  		}
   186  		if e := unstructuredObj.GetObjectKind().GroupVersionKind(); e != externalGVK {
   187  			t.Errorf("Unexpected object kind: %#v", e)
   188  		}
   189  	})
   190  	t.Run("Convert unstructured to unstructured", func(t *testing.T) {
   191  		uIn := &runtimetesting.Unstructured{Object: map[string]interface{}{
   192  			"test": []interface{}{"other", "test"},
   193  		}}
   194  		uOut := &runtimetesting.Unstructured{}
   195  		if err := scheme.Convert(uIn, uOut, nil); err != nil {
   196  			t.Fatalf("Unexpected error: %v", err)
   197  		}
   198  		if !reflect.DeepEqual(uIn.Object, uOut.Object) {
   199  			t.Errorf("Unexpected object contents: %#v", uOut.Object)
   200  		}
   201  	})
   202  	t.Run("Convert unstructured to structured", func(t *testing.T) {
   203  		unstructuredObj := &runtimetesting.Unstructured{
   204  			Object: map[string]interface{}{
   205  				"testString": "bla",
   206  			},
   207  		}
   208  		unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple"))
   209  		externalOut := &runtimetesting.ExternalSimple{}
   210  		if err := scheme.Convert(unstructuredObj, externalOut, nil); err != nil {
   211  			t.Fatalf("Unexpected error: %v", err)
   212  		}
   213  		if externalOut.TestString != "bla" {
   214  			t.Errorf("Unexpected object contents: %#v", externalOut)
   215  		}
   216  	})
   217  	t.Run("Encode and Convert should each have caused an increment", func(t *testing.T) {
   218  		if e, a := 3, conversions.internalToExternalCalls; e != a {
   219  			t.Errorf("Expected %v, got %v", e, a)
   220  		}
   221  	})
   222  	t.Run("DecodeInto and Decode should each have caused an increment because of a conversion", func(t *testing.T) {
   223  		if e, a := 2, conversions.externalToInternalCalls; e != a {
   224  			t.Errorf("Expected %v, got %v", e, a)
   225  		}
   226  	})
   227  	t.Run("Verify that unstructured types must have V and K set", func(t *testing.T) {
   228  		emptyObj := &runtimetesting.Unstructured{Object: make(map[string]interface{})}
   229  		if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingKind(err) {
   230  			t.Errorf("unexpected error: %v", err)
   231  		}
   232  		emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test"})
   233  		if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingVersion(err) {
   234  			t.Errorf("unexpected error: %v", err)
   235  		}
   236  		emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test", Version: "v1"})
   237  		if _, _, err := scheme.ObjectKinds(emptyObj); err != nil {
   238  			t.Errorf("unexpected error: %v", err)
   239  		}
   240  	})
   241  }
   242  
   243  func TestBadJSONRejection(t *testing.T) {
   244  	scheme := runtime.NewScheme()
   245  	codecs := serializer.NewCodecFactory(scheme)
   246  	info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
   247  	jsonserializer := info.Serializer
   248  
   249  	badJSONMissingKind := []byte(`{ }`)
   250  	if _, err := runtime.Decode(jsonserializer, badJSONMissingKind); err == nil {
   251  		t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
   252  	}
   253  	badJSONUnknownType := []byte(`{"kind": "bar"}`)
   254  	if _, err1 := runtime.Decode(jsonserializer, badJSONUnknownType); err1 == nil {
   255  		t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
   256  	}
   257  }
   258  
   259  func TestExternalToInternalMapping(t *testing.T) {
   260  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
   261  	externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
   262  
   263  	scheme := runtime.NewScheme()
   264  	scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{})
   265  	scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{})
   266  	utilruntime.Must(runtimetesting.RegisterConversions(scheme))
   267  
   268  	codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
   269  
   270  	table := []struct {
   271  		obj     runtime.Object
   272  		encoded string
   273  	}{
   274  		{
   275  			&runtimetesting.InternalOptionalExtensionType{Extension: nil},
   276  			`{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`,
   277  		},
   278  	}
   279  
   280  	for i, item := range table {
   281  		gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
   282  		if err != nil {
   283  			t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
   284  		} else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) {
   285  			t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
   286  		}
   287  	}
   288  }
   289  
   290  func TestExtensionMapping(t *testing.T) {
   291  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
   292  	externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
   293  
   294  	scheme := runtime.NewScheme()
   295  	scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &runtimetesting.InternalExtensionType{})
   296  	scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{})
   297  	scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &runtimetesting.ExternalExtensionType{})
   298  	scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{})
   299  
   300  	// register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the
   301  	// external version.
   302  	scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &runtimetesting.ExtensionA{})
   303  	scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &runtimetesting.ExtensionB{})
   304  	scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &runtimetesting.ExtensionA{})
   305  	scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &runtimetesting.ExtensionB{})
   306  	utilruntime.Must(runtimetesting.RegisterConversions(scheme))
   307  
   308  	codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
   309  
   310  	table := []struct {
   311  		obj      runtime.Object
   312  		expected runtime.Object
   313  		encoded  string
   314  	}{
   315  		{
   316  			&runtimetesting.InternalExtensionType{
   317  				Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionA{TestString: "foo"}),
   318  			},
   319  			&runtimetesting.InternalExtensionType{
   320  				Extension: &runtime.Unknown{
   321  					Raw:         []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`),
   322  					ContentType: runtime.ContentTypeJSON,
   323  				},
   324  			},
   325  			// apiVersion is set in the serialized object for easier consumption by clients
   326  			`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}}
   327  `,
   328  		}, {
   329  			&runtimetesting.InternalExtensionType{Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionB{TestString: "bar"})},
   330  			&runtimetesting.InternalExtensionType{
   331  				Extension: &runtime.Unknown{
   332  					Raw:         []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`),
   333  					ContentType: runtime.ContentTypeJSON,
   334  				},
   335  			},
   336  			// apiVersion is set in the serialized object for easier consumption by clients
   337  			`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}}
   338  `,
   339  		}, {
   340  			&runtimetesting.InternalExtensionType{Extension: nil},
   341  			&runtimetesting.InternalExtensionType{
   342  				Extension: nil,
   343  			},
   344  			`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null}
   345  `,
   346  		},
   347  	}
   348  
   349  	for i, item := range table {
   350  		gotEncoded, err := runtime.Encode(codec, item.obj)
   351  		if err != nil {
   352  			t.Errorf("unexpected error '%v' (%#v)", err, item.obj)
   353  		} else if e, a := item.encoded, string(gotEncoded); e != a {
   354  			t.Errorf("expected\n%#v\ngot\n%#v\n", e, a)
   355  		}
   356  
   357  		gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
   358  		if err != nil {
   359  			t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
   360  		} else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) {
   361  			t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
   362  		}
   363  	}
   364  }
   365  
   366  func TestEncode(t *testing.T) {
   367  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
   368  	internalGVK := internalGV.WithKind("Simple")
   369  	externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
   370  	externalGVK := externalGV.WithKind("Simple")
   371  
   372  	scheme := runtime.NewScheme()
   373  	scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{})
   374  	scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{})
   375  	utilruntime.Must(runtimetesting.RegisterConversions(scheme))
   376  
   377  	codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
   378  
   379  	test := &runtimetesting.InternalSimple{
   380  		TestString: "I'm the same",
   381  	}
   382  	obj := runtime.Object(test)
   383  	data, err := runtime.Encode(codec, obj)
   384  	obj2, gvk, err2 := codec.Decode(data, nil, nil)
   385  	if err != nil || err2 != nil {
   386  		t.Fatalf("Failure: '%v' '%v'", err, err2)
   387  	}
   388  	if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
   389  		t.Fatalf("Got wrong type")
   390  	}
   391  	if !reflect.DeepEqual(obj2, test) {
   392  		t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
   393  	}
   394  	if *gvk != externalGVK {
   395  		t.Errorf("unexpected gvk returned by decode: %#v", *gvk)
   396  	}
   397  }
   398  
   399  func TestUnversionedTypes(t *testing.T) {
   400  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
   401  	internalGVK := internalGV.WithKind("Simple")
   402  	externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
   403  	externalGVK := externalGV.WithKind("Simple")
   404  	otherGV := schema.GroupVersion{Group: "group", Version: "other"}
   405  
   406  	scheme := runtime.NewScheme()
   407  	scheme.AddUnversionedTypes(externalGV, &runtimetesting.InternalSimple{})
   408  	scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{})
   409  	scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{})
   410  	scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
   411  	utilruntime.Must(runtimetesting.RegisterConversions(scheme))
   412  
   413  	codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
   414  
   415  	if unv, ok := scheme.IsUnversioned(&runtimetesting.InternalSimple{}); !unv || !ok {
   416  		t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok)
   417  	}
   418  
   419  	kinds, _, err := scheme.ObjectKinds(&runtimetesting.InternalSimple{})
   420  	if err != nil {
   421  		t.Fatal(err)
   422  	}
   423  	kind := kinds[0]
   424  	if kind != externalGV.WithKind("InternalSimple") {
   425  		t.Fatalf("unexpected: %#v", kind)
   426  	}
   427  
   428  	test := &runtimetesting.InternalSimple{
   429  		TestString: "I'm the same",
   430  	}
   431  	obj := runtime.Object(test)
   432  	data, err := runtime.Encode(codec, obj)
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	obj2, gvk, err := codec.Decode(data, nil, nil)
   437  	if err != nil {
   438  		t.Fatal(err)
   439  	}
   440  	if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
   441  		t.Fatalf("Got wrong type")
   442  	}
   443  	if !reflect.DeepEqual(obj2, test) {
   444  		t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
   445  	}
   446  	// object is serialized as an unversioned object (in the group and version it was defined in)
   447  	if *gvk != externalGV.WithKind("InternalSimple") {
   448  		t.Errorf("unexpected gvk returned by decode: %#v", *gvk)
   449  	}
   450  
   451  	// when serialized to a different group, the object is kept in its preferred name
   452  	codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV)
   453  	data, err = runtime.Encode(codec, obj)
   454  	if err != nil {
   455  		t.Fatal(err)
   456  	}
   457  	if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" {
   458  		t.Errorf("unexpected data: %s", data)
   459  	}
   460  }
   461  
   462  // Returns a new Scheme set up with the test objects.
   463  func GetTestScheme() *runtime.Scheme {
   464  	internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
   465  	externalGV := schema.GroupVersion{Version: "v1"}
   466  	alternateExternalGV := schema.GroupVersion{Group: "custom", Version: "v1"}
   467  	alternateInternalGV := schema.GroupVersion{Group: "custom", Version: runtime.APIVersionInternal}
   468  	differentExternalGV := schema.GroupVersion{Group: "other", Version: "v2"}
   469  
   470  	s := runtime.NewScheme()
   471  	// Ordinarily, we wouldn't add TestType2, but because this is a test and
   472  	// both types are from the same package, we need to get it into the system
   473  	// so that converter will match it with ExternalType2.
   474  	s.AddKnownTypes(internalGV, &runtimetesting.TestType1{}, &runtimetesting.TestType2{}, &runtimetesting.ExternalInternalSame{})
   475  	s.AddKnownTypes(externalGV, &runtimetesting.ExternalInternalSame{})
   476  	s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
   477  	s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &runtimetesting.ExternalTestType2{})
   478  	s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &runtimetesting.TestType1{})
   479  	s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
   480  	s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &runtimetesting.ExternalTestType1{})
   481  	s.AddKnownTypeWithName(alternateInternalGV.WithKind("TestType3"), &runtimetesting.TestType1{})
   482  	s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
   483  	s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &runtimetesting.ExternalTestType1{})
   484  	s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
   485  	s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{})
   486  	utilruntime.Must(runtimetesting.RegisterConversions(s))
   487  
   488  	return s
   489  }
   490  
   491  func TestKnownTypes(t *testing.T) {
   492  	s := GetTestScheme()
   493  	if len(s.KnownTypes(schema.GroupVersion{Group: "group", Version: "v2"})) != 0 {
   494  		t.Errorf("should have no known types for v2")
   495  	}
   496  
   497  	types := s.KnownTypes(schema.GroupVersion{Version: "v1"})
   498  	for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} {
   499  		if _, ok := types[s]; !ok {
   500  			t.Errorf("missing type %q", s)
   501  		}
   502  	}
   503  }
   504  
   505  func TestAddKnownTypesIdemPotent(t *testing.T) {
   506  	s := runtime.NewScheme()
   507  
   508  	gv := schema.GroupVersion{Group: "foo", Version: "v1"}
   509  	s.AddKnownTypes(gv, &runtimetesting.InternalSimple{})
   510  	s.AddKnownTypes(gv, &runtimetesting.InternalSimple{})
   511  	if len(s.KnownTypes(gv)) != 1 {
   512  		t.Errorf("expected only one %v type after double registration", gv)
   513  	}
   514  	if len(s.AllKnownTypes()) != 1 {
   515  		t.Errorf("expected only one type after double registration")
   516  	}
   517  
   518  	s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
   519  	s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
   520  	if len(s.KnownTypes(gv)) != 1 {
   521  		t.Errorf("expected only one %v type after double registration with custom name", gv)
   522  	}
   523  	if len(s.AllKnownTypes()) != 1 {
   524  		t.Errorf("expected only one type after double registration with custom name")
   525  	}
   526  
   527  	s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
   528  	s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
   529  	if len(s.KnownTypes(gv)) != 1 {
   530  		t.Errorf("expected only one %v type after double registration with custom name", gv)
   531  	}
   532  	if len(s.AllKnownTypes()) != 1 {
   533  		t.Errorf("expected only one type after double registration with custom name")
   534  	}
   535  
   536  	kinds, _, err := s.ObjectKinds(&runtimetesting.InternalSimple{})
   537  	if err != nil {
   538  		t.Fatalf("unexpected error: %v", err)
   539  	}
   540  	if len(kinds) != 1 {
   541  		t.Errorf("expected only one kind for InternalSimple after double registration")
   542  	}
   543  }
   544  
   545  // redefine InternalSimple with the same name, but obviously as a different type than in runtimetesting
   546  type InternalSimple struct {
   547  	runtime.TypeMeta `json:",inline"`
   548  	TestString       string `json:"testString"`
   549  }
   550  
   551  func (s *InternalSimple) DeepCopyObject() runtime.Object { return nil }
   552  
   553  func TestConflictingAddKnownTypes(t *testing.T) {
   554  	s := runtime.NewScheme()
   555  	gv := schema.GroupVersion{Group: "foo", Version: "v1"}
   556  
   557  	panicked := make(chan bool)
   558  	go func() {
   559  		defer func() {
   560  			if recover() != nil {
   561  				panicked <- true
   562  			}
   563  		}()
   564  		s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
   565  		s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.ExternalSimple{})
   566  		panicked <- false
   567  	}()
   568  	if !<-panicked {
   569  		t.Errorf("Expected AddKnownTypesWithName to panic with conflicting type registrations")
   570  	}
   571  
   572  	go func() {
   573  		defer func() {
   574  			if recover() != nil {
   575  				panicked <- true
   576  			}
   577  		}()
   578  
   579  		s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
   580  		s.AddUnversionedTypes(gv, &InternalSimple{})
   581  		panicked <- false
   582  	}()
   583  	if !<-panicked {
   584  		t.Errorf("Expected AddUnversionedTypes to panic with conflicting type registrations")
   585  	}
   586  }
   587  
   588  func TestConvertToVersionBasic(t *testing.T) {
   589  	s := GetTestScheme()
   590  	tt := &runtimetesting.TestType1{A: "I'm not a pointer object"}
   591  	other, err := s.ConvertToVersion(tt, schema.GroupVersion{Version: "v1"})
   592  	if err != nil {
   593  		t.Fatalf("Failure: %v", err)
   594  	}
   595  	converted, ok := other.(*runtimetesting.ExternalTestType1)
   596  	if !ok {
   597  		t.Fatalf("Got wrong type: %T", other)
   598  	}
   599  	if tt.A != converted.A {
   600  		t.Fatalf("Failed to convert object correctly: %#v", converted)
   601  	}
   602  }
   603  
   604  type testGroupVersioner struct {
   605  	target schema.GroupVersionKind
   606  	ok     bool
   607  }
   608  
   609  func (m testGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
   610  	return m.target, m.ok
   611  }
   612  
   613  func (m testGroupVersioner) Identifier() string {
   614  	return "testGroupVersioner"
   615  }
   616  
   617  func TestConvertToVersion(t *testing.T) {
   618  	testCases := []struct {
   619  		scheme *runtime.Scheme
   620  		in     runtime.Object
   621  		gv     runtime.GroupVersioner
   622  		same   bool
   623  		out    runtime.Object
   624  		errFn  func(error) bool
   625  	}{
   626  		// errors if the type is not registered in the scheme
   627  		{
   628  			scheme: GetTestScheme(),
   629  			in:     &runtimetesting.UnknownType{},
   630  			errFn:  func(err error) bool { return err != nil && runtime.IsNotRegisteredError(err) },
   631  		},
   632  		// errors if the group versioner returns no target
   633  		{
   634  			scheme: GetTestScheme(),
   635  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   636  			gv:     testGroupVersioner{},
   637  			errFn: func(err error) bool {
   638  				return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
   639  			},
   640  		},
   641  		// converts to internal
   642  		{
   643  			scheme: GetTestScheme(),
   644  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   645  			gv:     schema.GroupVersion{Version: runtime.APIVersionInternal},
   646  			out:    &runtimetesting.TestType1{A: "test"},
   647  		},
   648  		// converts from unstructured to internal
   649  		{
   650  			scheme: GetTestScheme(),
   651  			in: &runtimetesting.Unstructured{Object: map[string]interface{}{
   652  				"apiVersion": "custom/v1",
   653  				"kind":       "TestType3",
   654  				"A":          "test",
   655  			}},
   656  			gv:  schema.GroupVersion{Version: runtime.APIVersionInternal},
   657  			out: &runtimetesting.TestType1{A: "test"},
   658  		},
   659  		// converts from unstructured to external
   660  		{
   661  			scheme: GetTestScheme(),
   662  			in: &runtimetesting.Unstructured{Object: map[string]interface{}{
   663  				"apiVersion": "custom/v1",
   664  				"kind":       "TestType3",
   665  				"A":          "test",
   666  			}},
   667  			gv:  schema.GroupVersion{Group: "custom", Version: "v1"},
   668  			out: &runtimetesting.ExternalTestType1{MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"}, A: "test"},
   669  		},
   670  		// prefers the best match
   671  		{
   672  			scheme: GetTestScheme(),
   673  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   674  			gv:     schema.GroupVersions{{Version: runtime.APIVersionInternal}, {Version: "v1"}},
   675  			out: &runtimetesting.ExternalTestType1{
   676  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   677  				A:                                     "test",
   678  			},
   679  		},
   680  		// unversioned type returned as-is
   681  		{
   682  			scheme: GetTestScheme(),
   683  			in:     &runtimetesting.UnversionedType{A: "test"},
   684  			gv:     schema.GroupVersions{{Version: "v1"}},
   685  			same:   true,
   686  			out: &runtimetesting.UnversionedType{
   687  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
   688  				A:                                     "test",
   689  			},
   690  		},
   691  		// unversioned type returned when not included in the target types
   692  		{
   693  			scheme: GetTestScheme(),
   694  			in:     &runtimetesting.UnversionedType{A: "test"},
   695  			gv:     schema.GroupVersions{{Group: "other", Version: "v2"}},
   696  			same:   true,
   697  			out: &runtimetesting.UnversionedType{
   698  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
   699  				A:                                     "test",
   700  			},
   701  		},
   702  		// detected as already being in the target version
   703  		{
   704  			scheme: GetTestScheme(),
   705  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   706  			gv:     schema.GroupVersions{{Version: "v1"}},
   707  			same:   true,
   708  			out: &runtimetesting.ExternalTestType1{
   709  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   710  				A:                                     "test",
   711  			},
   712  		},
   713  		// detected as already being in the first target version
   714  		{
   715  			scheme: GetTestScheme(),
   716  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   717  			gv:     schema.GroupVersions{{Version: "v1"}, {Version: runtime.APIVersionInternal}},
   718  			same:   true,
   719  			out: &runtimetesting.ExternalTestType1{
   720  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   721  				A:                                     "test",
   722  			},
   723  		},
   724  		// detected as already being in the first target version
   725  		{
   726  			scheme: GetTestScheme(),
   727  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   728  			gv:     schema.GroupVersions{{Version: "v1"}, {Version: runtime.APIVersionInternal}},
   729  			same:   true,
   730  			out: &runtimetesting.ExternalTestType1{
   731  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   732  				A:                                     "test",
   733  			},
   734  		},
   735  		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (1/3): different kind
   736  		{
   737  			scheme: GetTestScheme(),
   738  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   739  			gv:     testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Version: "v1"}},
   740  			same:   true,
   741  			out: &runtimetesting.ExternalTestType1{
   742  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
   743  				A:                                     "test",
   744  			},
   745  		},
   746  		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (2/3): different gv
   747  		{
   748  			scheme: GetTestScheme(),
   749  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   750  			gv:     testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Group: "custom", Version: "v1"}},
   751  			same:   true,
   752  			out: &runtimetesting.ExternalTestType1{
   753  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"},
   754  				A:                                     "test",
   755  			},
   756  		},
   757  		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (3/3): different gvk
   758  		{
   759  			scheme: GetTestScheme(),
   760  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   761  			gv:     testGroupVersioner{ok: true, target: schema.GroupVersionKind{Group: "custom", Version: "v1", Kind: "TestType5"}},
   762  			same:   true,
   763  			out: &runtimetesting.ExternalTestType1{
   764  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
   765  				A:                                     "test",
   766  			},
   767  		},
   768  		// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
   769  		{
   770  			scheme: GetTestScheme(),
   771  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   772  			gv:     runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
   773  			out: &runtimetesting.ExternalTestType1{
   774  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
   775  				A:                                     "test",
   776  			},
   777  		},
   778  		// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
   779  		{
   780  			scheme: GetTestScheme(),
   781  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   782  			gv:     runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
   783  			out: &runtimetesting.ExternalTestType1{
   784  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
   785  				A:                                     "test",
   786  			},
   787  		},
   788  		// 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)
   789  		{
   790  			scheme: GetTestScheme(),
   791  			in:     &runtimetesting.TestType1{A: "test"},
   792  			gv:     runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "custom", Version: "v1"}, schema.GroupKind{Group: "other"}, schema.GroupKind{Kind: "TestType5"}),
   793  			errFn: func(err error) bool {
   794  				return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
   795  			},
   796  		},
   797  		// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
   798  		{
   799  			scheme: GetTestScheme(),
   800  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   801  			gv:     runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
   802  			same:   true,
   803  			out: &runtimetesting.ExternalTestType1{
   804  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   805  				A:                                     "test",
   806  			},
   807  		},
   808  		// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
   809  		{
   810  			scheme: GetTestScheme(),
   811  			in:     &runtimetesting.ExternalTestType1{A: "test"},
   812  			gv:     runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
   813  			same:   true,
   814  			out: &runtimetesting.ExternalTestType1{
   815  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
   816  				A:                                     "test",
   817  			},
   818  		},
   819  		// group versioner can choose a particular target kind for a given input when kind is the same across group versions
   820  		{
   821  			scheme: GetTestScheme(),
   822  			in:     &runtimetesting.TestType1{A: "test"},
   823  			gv:     testGroupVersioner{ok: true, target: schema.GroupVersionKind{Version: "v1", Kind: "TestType3"}},
   824  			out: &runtimetesting.ExternalTestType1{
   825  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
   826  				A:                                     "test",
   827  			},
   828  		},
   829  		// group versioner can choose a different kind
   830  		{
   831  			scheme: GetTestScheme(),
   832  			in:     &runtimetesting.TestType1{A: "test"},
   833  			gv:     testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType5", Group: "custom", Version: "v1"}},
   834  			out: &runtimetesting.ExternalTestType1{
   835  				MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
   836  				A:                                     "test",
   837  			},
   838  		},
   839  	}
   840  	for i, test := range testCases {
   841  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   842  			original := test.in.DeepCopyObject()
   843  			out, err := test.scheme.ConvertToVersion(test.in, test.gv)
   844  			switch {
   845  			case test.errFn != nil:
   846  				if !test.errFn(err) {
   847  					t.Fatalf("unexpected error: %v", err)
   848  				}
   849  				return
   850  			case err != nil:
   851  				t.Fatalf("unexpected error: %v", err)
   852  			}
   853  			if out == test.in {
   854  				t.Fatalf("ConvertToVersion should always copy out: %#v", out)
   855  			}
   856  
   857  			if test.same {
   858  				if !reflect.DeepEqual(original, test.in) {
   859  					t.Fatalf("unexpected mutation of input: %s", diff.ObjectReflectDiff(original, test.in))
   860  				}
   861  				if !reflect.DeepEqual(out, test.out) {
   862  					t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out))
   863  				}
   864  				unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
   865  				if err != nil {
   866  					t.Fatalf("unexpected error: %v", err)
   867  				}
   868  				if !reflect.DeepEqual(unsafe, test.out) {
   869  					t.Fatalf("unexpected unsafe: %s", diff.ObjectReflectDiff(unsafe, test.out))
   870  				}
   871  				if unsafe != test.in {
   872  					t.Fatalf("UnsafeConvertToVersion should return same object: %#v", unsafe)
   873  				}
   874  				return
   875  			}
   876  			if !reflect.DeepEqual(out, test.out) {
   877  				t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out))
   878  			}
   879  		})
   880  	}
   881  }
   882  
   883  func TestConvert(t *testing.T) {
   884  	testCases := []struct {
   885  		scheme *runtime.Scheme
   886  		in     runtime.Object
   887  		into   runtime.Object
   888  		gv     runtime.GroupVersioner
   889  		out    runtime.Object
   890  		errFn  func(error) bool
   891  	}{
   892  		// converts from internal to unstructured, given a target version
   893  		{
   894  			scheme: GetTestScheme(),
   895  			in:     &runtimetesting.TestType1{A: "test"},
   896  			into:   &runtimetesting.Unstructured{},
   897  			out: &runtimetesting.Unstructured{Object: map[string]interface{}{
   898  				"myVersionKey": "custom/v1",
   899  				"myKindKey":    "TestType3",
   900  				"A":            "test",
   901  			}},
   902  			gv: schema.GroupVersion{Group: "custom", Version: "v1"},
   903  		},
   904  	}
   905  	for i, test := range testCases {
   906  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   907  			err := test.scheme.Convert(test.in, test.into, test.gv)
   908  			switch {
   909  			case test.errFn != nil:
   910  				if !test.errFn(err) {
   911  					t.Fatalf("unexpected error: %v", err)
   912  				}
   913  				return
   914  			case err != nil:
   915  				t.Fatalf("unexpected error: %v", err)
   916  				return
   917  			}
   918  
   919  			if !reflect.DeepEqual(test.into, test.out) {
   920  				t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(test.into, test.out))
   921  			}
   922  		})
   923  	}
   924  }
   925  
   926  func TestMetaValues(t *testing.T) {
   927  	internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
   928  	externalGV := schema.GroupVersion{Group: "test.group", Version: "externalVersion"}
   929  
   930  	s := runtime.NewScheme()
   931  	s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
   932  	s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
   933  	utilruntime.Must(runtimetesting.RegisterConversions(s))
   934  
   935  	conversions := &testConversions{
   936  		internalToExternalCalls: 0,
   937  		externalToInternalCalls: 0,
   938  	}
   939  
   940  	// Register functions to verify that scope.Meta() gets set correctly.
   941  	utilruntime.Must(conversions.registerConversions(s))
   942  
   943  	simple := &runtimetesting.InternalSimple{
   944  		TestString: "foo",
   945  	}
   946  
   947  	out, err := s.ConvertToVersion(simple, externalGV)
   948  	if err != nil {
   949  		t.Fatalf("unexpected error: %v", err)
   950  	}
   951  
   952  	internal, err := s.ConvertToVersion(out, internalGV)
   953  	if err != nil {
   954  		t.Fatalf("unexpected error: %v", err)
   955  	}
   956  
   957  	if e, a := simple, internal; !reflect.DeepEqual(e, a) {
   958  		t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
   959  	}
   960  
   961  	if e, a := 1, conversions.internalToExternalCalls; e != a {
   962  		t.Errorf("Expected %v, got %v", e, a)
   963  	}
   964  	if e, a := 1, conversions.externalToInternalCalls; e != a {
   965  		t.Errorf("Expected %v, got %v", e, a)
   966  	}
   967  }
   968  
   969  func TestMetaValuesUnregisteredConvert(t *testing.T) {
   970  	type InternalSimple struct {
   971  		Version    string `json:"apiVersion,omitempty"`
   972  		Kind       string `json:"kind,omitempty"`
   973  		TestString string `json:"testString"`
   974  	}
   975  	type ExternalSimple struct {
   976  		Version    string `json:"apiVersion,omitempty"`
   977  		Kind       string `json:"kind,omitempty"`
   978  		TestString string `json:"testString"`
   979  	}
   980  	s := runtime.NewScheme()
   981  	// We deliberately don't register the types.
   982  
   983  	internalToExternalCalls := 0
   984  
   985  	// Register functions to verify that scope.Meta() gets set correctly.
   986  	convertSimple := func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
   987  		out.TestString = in.TestString
   988  		internalToExternalCalls++
   989  		return nil
   990  	}
   991  	if err := s.AddConversionFunc((*InternalSimple)(nil), (*ExternalSimple)(nil), func(a, b interface{}, scope conversion.Scope) error {
   992  		return convertSimple(a.(*InternalSimple), b.(*ExternalSimple), scope)
   993  	}); err != nil {
   994  		t.Fatalf("unexpected error: %v", err)
   995  	}
   996  
   997  	simple := &InternalSimple{TestString: "foo"}
   998  	external := &ExternalSimple{}
   999  	if err := s.Convert(simple, external, nil); err != nil {
  1000  		t.Fatalf("Unexpected error: %v", err)
  1001  	}
  1002  	if e, a := simple.TestString, external.TestString; e != a {
  1003  		t.Errorf("Expected %v, got %v", e, a)
  1004  	}
  1005  
  1006  	// Verify that our conversion handler got called.
  1007  	if e, a := 1, internalToExternalCalls; e != a {
  1008  		t.Errorf("Expected %v, got %v", e, a)
  1009  	}
  1010  }