Conversion from typed to unstructured should set GVK

This commit is contained in:
Mikhail Mazurskiy 2018-02-02 23:26:04 +11:00
parent d8605eb7eb
commit cd8fd313bb
No known key found for this signature in database
GPG Key ID: 93551ECC96E2F568
3 changed files with 166 additions and 130 deletions

View File

@ -431,6 +431,7 @@ func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
return err
}
unstructuredOut.SetUnstructuredContent(content)
unstructuredOut.GetObjectKind().SetGroupVersionKind(gvk)
return nil
}

View File

@ -55,14 +55,26 @@ func TestScheme(t *testing.T) {
// Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs(
func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0)
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 {
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0)
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
},
@ -71,140 +83,160 @@ func TestScheme(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
codecs := serializer.NewCodecFactory(scheme)
codec := codecs.LegacyCodec(externalGV)
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
jsonserializer := info.Serializer
t.Run("Encode, Decode, DecodeInto, and DecodeToVersion", func(t *testing.T) {
simple := &runtimetesting.InternalSimple{
TestString: "foo",
}
simple := &runtimetesting.InternalSimple{
TestString: "foo",
}
codecs := serializer.NewCodecFactory(scheme)
codec := codecs.LegacyCodec(externalGV)
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
jsonserializer := info.Serializer
// Test Encode, Decode, DecodeInto, and DecodeToVersion
obj := runtime.Object(simple)
data, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
obj := runtime.Object(simple)
data, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatal(err)
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
t.Fatalf("Got wrong type")
}
if e, a := simple, obj2; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
t.Fatalf("Got wrong type")
}
if e, a := simple, obj2; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj3 := &runtimetesting.InternalSimple{}
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Fatal(err)
}
// clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion
// does not automatically clear TypeMeta anymore).
simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()}
if e, a := simple, obj3; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj3 := &runtimetesting.InternalSimple{}
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Fatal(err)
}
// clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion
// does not automatically clear TypeMeta anymore).
simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()}
if e, a := simple, obj3; !reflect.DeepEqual(e, a) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
}
obj4, err := runtime.Decode(jsonserializer, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj4.(*runtimetesting.ExternalSimple); !ok {
t.Fatalf("Got wrong type")
}
obj4, err := runtime.Decode(jsonserializer, data)
if err != nil {
t.Fatal(err)
}
if _, ok := obj4.(*runtimetesting.ExternalSimple); !ok {
t.Fatalf("Got wrong type")
}
})
t.Run("Convert", func(t *testing.T) {
simple := &runtimetesting.InternalSimple{
TestString: "foo",
}
// Test Convert
external := &runtimetesting.ExternalSimple{}
err = scheme.Convert(simple, external, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
external := &runtimetesting.ExternalSimple{}
err = scheme.Convert(simple, external, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, external.TestString; e != a {
t.Errorf("Expected %q, got %q", e, a)
}
})
t.Run("Convert internal to unstructured", func(t *testing.T) {
simple := &runtimetesting.InternalSimple{
TestString: "foo",
}
// Test convert internal to unstructured
unstructuredObj := &runtimetesting.Unstructured{}
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, schema.GroupVersion{Group: "test.group", Version: "testExternal"})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
if gvks, unversioned, err := scheme.ObjectKinds(unstructuredObj); err != nil || !reflect.DeepEqual(gvks[0], schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) || unversioned {
t.Errorf("Scheme did not recognize unversioned: %v, %#v %t", err, gvks, unversioned)
}
unstructuredObj := &runtimetesting.Unstructured{}
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, schema.GroupVersion{Group: "test.group", Version: "testExternal"})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %q, got %q", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
if gvks, unversioned, err := scheme.ObjectKinds(unstructuredObj); err != nil || !reflect.DeepEqual(gvks[0], schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) || unversioned {
t.Errorf("Scheme did not recognize unversioned: %v, %#v %t", err, gvks, unversioned)
}
})
t.Run("Convert external to unstructured", func(t *testing.T) {
unstructuredObj := &runtimetesting.Unstructured{}
external := &runtimetesting.ExternalSimple{
TestString: "foo",
}
// Test convert external to unstructured
unstructuredObj = &runtimetesting.Unstructured{}
err = scheme.Convert(external, unstructuredObj, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
// Test convert unstructured to unstructured
uIn := &runtimetesting.Unstructured{Object: map[string]interface{}{
"test": []interface{}{"other", "test"},
}}
uOut := &runtimetesting.Unstructured{}
err = scheme.Convert(uIn, uOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(uIn.Object, uOut.Object) {
t.Errorf("Unexpected object contents: %#v", uOut.Object)
}
// Test convert unstructured to structured
externalOut := &runtimetesting.ExternalSimple{}
err = scheme.Convert(unstructuredObj, externalOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(external, externalOut) {
t.Errorf("Unexpected object contents: %#v", externalOut)
}
// Encode and Convert should each have caused an increment.
if e, a := 3, internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// DecodeInto and Decode should each have caused an increment because of a conversion
if e, a := 2, externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// Verify that unstructured types must have V and K set
emptyObj := &runtimetesting.Unstructured{Object: make(map[string]interface{})}
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingKind(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test"})
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingVersion(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test", Version: "v1"})
if _, _, err := scheme.ObjectKinds(emptyObj); err != nil {
t.Errorf("unexpected error: %v", err)
}
err = scheme.Convert(external, unstructuredObj, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %q, got %q", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
})
t.Run("Convert unstructured to unstructured", func(t *testing.T) {
uIn := &runtimetesting.Unstructured{Object: map[string]interface{}{
"test": []interface{}{"other", "test"},
}}
uOut := &runtimetesting.Unstructured{}
err = scheme.Convert(uIn, uOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(uIn.Object, uOut.Object) {
t.Errorf("Unexpected object contents: %#v", uOut.Object)
}
})
t.Run("Convert unstructured to structured", func(t *testing.T) {
unstructuredObj := &runtimetesting.Unstructured{
Object: map[string]interface{}{
"testString": "bla",
},
}
unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple"))
externalOut := &runtimetesting.ExternalSimple{}
err = scheme.Convert(unstructuredObj, externalOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if externalOut.TestString != "bla" {
t.Errorf("Unexpected object contents: %#v", externalOut)
}
})
t.Run("Encode and Convert should each have caused an increment", func(t *testing.T) {
if e, a := 3, 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 {
t.Errorf("Expected %v, got %v", e, a)
}
})
t.Run("Verify that unstructured types must have V and K set", func(t *testing.T) {
emptyObj := &runtimetesting.Unstructured{Object: make(map[string]interface{})}
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingKind(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test"})
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingVersion(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test", Version: "v1"})
if _, _, err := scheme.ObjectKinds(emptyObj); err != nil {
t.Errorf("unexpected error: %v", err)
}
})
}
func TestBadJSONRejection(t *testing.T) {

View File

@ -315,6 +315,9 @@ func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
}
func (u *Unstructured) SetGroupVersionKind(gvk schema.GroupVersionKind) {
if u.Object == nil {
u.Object = make(map[string]interface{})
}
u.Object["apiVersion"] = gvk.GroupVersion().String()
u.Object["kind"] = gvk.Kind
}